diff --git a/Readme.md b/Readme.md
index 756d8f9af..54570981c 100644
--- a/Readme.md
+++ b/Readme.md
@@ -55,9 +55,9 @@ If you're using Slate for the first time, check out the [Getting Started](./docs
- [**Guides**](docs/guides/installing-slate.md)
- [Installing Slate](docs/guides/installing-slate.md)
- [Adding Event Handlers](docs/guides/adding-event-handlers.md)
- - [Adding Custom Formatting](docs/guides/adding-custom-formatting.md)
- - [Adding Custom Block Types](docs/guides/adding-custom-block-types.md)
- - Adding Plugins
+ - [Defining Custom Block Nodes](docs/guides/defining-custom-block-nodes.md)
+ - [Applying Custom Formatting](docs/guides/applying-custom-formatting.md)
+ - [Using Plugins](docs/guides/using-plugins.md)
- [**Concepts**](docs/concepts.md)
- Statelessness & Immutability
diff --git a/docs/guides/Readme.md b/docs/guides/Readme.md
index f69e8818a..45346a384 100644
--- a/docs/guides/Readme.md
+++ b/docs/guides/Readme.md
@@ -3,8 +3,8 @@ These guides introduce you to the different parts of Slate in a step-by-step way
- [Installing Slate](./installing-slate.md)
- [Adding Event Handlers](./adding-event-handlers.md)
-- [Adding Custom Formatting](./adding-custom-formatting.md)
-- [Adding Custom Block Types](./adding-custom-block-types.md)
-- Adding Plugins
+- [Defining Custom Block Nodes](./defining-custom-block-nodes.md)
+- [Applying Custom Formatting](./applying-custom-formatting.md)
+- [Using Plugins](./using-plugins.md)
_If you have an idea for a guide, or notice something that isn't clear, submit a pull request!_
diff --git a/docs/guides/applying-custom-formatting.md b/docs/guides/applying-custom-formatting.md
index 7c1df477f..988d4c46b 100644
--- a/docs/guides/applying-custom-formatting.md
+++ b/docs/guides/applying-custom-formatting.md
@@ -253,7 +253,7 @@ class App extends React.Component {
const isBold = state.marks.some(mark => mark.type == 'bold')
return state
.transform()
- [isBold ? 'mark' : 'unmark']('bold')
+ [isBold ? 'unmark' : 'mark']('bold')
.apply()
}
case 192: {
diff --git a/docs/guides/using-plugins.md b/docs/guides/using-plugins.md
new file mode 100644
index 000000000..eb6f5ac60
--- /dev/null
+++ b/docs/guides/using-plugins.md
@@ -0,0 +1,338 @@
+
+
+
Previous:
Applying Custom Formatting
+
+
+### Using Formatting
+
+Up to now, everything we've learned has been about how to write one-off logic for your specific Slate editor. But one of the most beautiful things about Slate is actually its plugin system, and how it lets you write less one-off code.
+
+In the previous guide, we actually wrote some pretty useful code for adding **bold** formatting to ranges of text when a key is pressed. But most of that code wasn't really specific to bold text.
+
+So let's look at how you'd break that code out into it's own reusable plugin that can toggle _any_ formatting mark on _any_ key press.
+
+Starting with our app from earlier:
+
+```js
+const BOLD_MARK = {
+ fontWeight: 'bold'
+}
+
+class App extends React.Component {
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ state: initialState
+ }
+ }
+
+ render() {
+ return (
+ this.renderMark(mark)}
+ renderNode={node => this.renderNode(node)}
+ onChange={state => this.onChange(state)}
+ onKeyDown={(e, state) => this.onKeyDown(e, state)}
+ />
+ )
+ }
+
+ renderMark(mark) {
+ if (mark.type == 'bold') return BOLD_MARK
+ }
+
+ renderNode(node) {
+ if (node.type == 'paragraph') return ParagraphNode
+ }
+
+ onChange(state) {
+ this.setState({ state })
+ }
+
+ onKeyDown(event, state) {
+ if (!event.metaKey || event.which != 66) return
+
+ const isBold = state.marks.some(mark => mark.type == 'bold')
+ return state
+ .transform()
+ [isBold ? 'unmark' : 'mark']('bold')
+ .apply()
+ }
+
+}
+```
+
+Let's write a new function, that takes a set of options: the mark `type` to toggle and the key `code` to press.
+
+```js
+function MarkHotkey(options) {
+ // Grab our options from the ones passed in.
+ const { type, code } = options
+}
+```
+
+Okay, that was easy.
+
+Now we want to have it return a dictionary of handlers, in this case specifically containing a `onKeyDown` handler with logic pulled from our app:
+
+
+```js
+function MarkHotkey(options) {
+ const { type, code } = options
+
+ // Return our "plugin" object, containing the `onKeyDown` handler.
+ return {
+ onKeyDown(event, state) {
+ // Check that the key pressed matches our `code` option.
+ if (!event.metaKey || event.which != code) return
+
+ // Determine whether our `type` option mark is currently active.
+ const isActive = state.marks.some(mark => mark.type == type)
+
+ // Toggle the mark `type` based on whether it is active.
+ return state
+ .transform()
+ [isActive ? 'unmark' : 'mark'](type)
+ .apply()
+ }
+ }
+}
+```
+
+Boom! Now we're getting somewhere. That code is reusable for any type of mark.
+
+So now, let's remove the old code from our app, and pass the editor our brand new `MarkHotkey` plugin instead, giving it the same options that will keep our bold functionality intact:
+
+```js
+const BOLD_MARK = {
+ fontWeight: 'bold'
+}
+
+// Initialize our bold-mark-adding plugin.
+const boldPlugin = MarkHotkey({
+ type: 'bold',
+ code: 66
+})
+
+// Create an array of plugins.
+const plugins = [
+ boldPlugin
+]
+
+class App extends React.Component {
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ state: initialState
+ }
+ }
+
+ // Add the `plugins` property to the editor, and remove `onKeyDown`.
+ render() {
+ return (
+ this.renderMark(mark)}
+ renderNode={node => this.renderNode(node)}
+ onChange={state => this.onChange(state)}
+ />
+ )
+ }
+
+ renderMark(mark) {
+ if (mark.type == 'bold') return BOLD_MARK
+ }
+
+ renderNode(node) {
+ if (node.type == 'paragraph') return ParagraphNode
+ }
+
+ onChange(state) {
+ this.setState({ state })
+ }
+
+}
+```
+
+Awesome. If you test out the editor now, you'll notice that everything still works just as it did before. But the beauty of the logic being encapsulated in a plugin is that we can add more mark types _extremely_ easily now!
+
+Let's add _italic_, `code`, ~~strikethrough~~ and underline marks:
+
+```js
+// Add our new mark renderers...
+const MARKS = {
+ bold: {
+ fontWeight: 'bold'
+ },
+ code: {
+ fontFamily: 'monospace'
+ },
+ italic: {
+ fontStyle: 'italic'
+ },
+ strikethrough: {
+ textDecoration: 'strikethrough'
+ },
+ underline: {
+ textDecoration: 'underline'
+ }
+}
+
+// Initialize our plugins...
+const plugins = [
+ MarkHotkey({ code: 66, type: 'bold' }),
+ MarkHotkey({ code: 192, type: 'code' }),
+ MarkHotkey({ code: 73, type: 'italic' }),
+ MarkHotkey({ code: 68, type: 'strikethrough' }),
+ MarkHotkey({ code: 85, type: 'underline' })
+]
+
+class App extends React.Component {
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ state: initialState
+ }
+ }
+
+ render() {
+ return (
+ this.renderMark(mark)}
+ renderNode={node => this.renderNode(node)}
+ onChange={state => this.onChange(state)}
+ />
+ )
+ }
+
+ // Update our render function to handle all the new marks...
+ renderMark(mark) {
+ return MARKS[mark.type]
+ }
+
+ renderNode(node) {
+ if (node.type == 'paragraph') return ParagraphNode
+ }
+
+ onChange(state) {
+ this.setState({ state })
+ }
+
+}
+```
+
+And there you have it! We just added a ton of functionality to the editor with very little work. And we can keep all of our mark hotkey logic tested and isolated in a single place, making maintaining the code easier.
+
+Of course... now that it's reusable, we could actually make our `MarkHotkey` plugin a little easier to use. What if instead of a `code` argument it took the text of the `key` itself? That would make the calling code a lot clearer, since key codes are really obtuse.
+
+In fact, unless you have weirdly good keycode guessing, there's a good chance you had no idea what our current hotkeys bindings actually mapped to.
+
+Let's fix that.
+
+Using the `keycode` module in npm makes this dead simple.
+
+First install it:
+
+```
+npm install keycode
+```
+
+And then we can add it our plugin:
+
+```js
+// Import the keycode module.
+import keycode from `keycode`
+
+function MarkHotkey(options) {
+ // Change the options to take a `key`.
+ const { type, key } = options
+
+ return {
+ onKeyDown(event, state) {
+ // Change the comparison to use the key name.
+ if (!event.metaKey || keycode(event.which) != key) return
+
+ const isActive = state.marks.some(mark => mark.type == type)
+ return state
+ .transform()
+ [isActive ? 'unmark' : 'mark'](type)
+ .apply()
+ }
+ }
+}
+```
+
+And finally, we can make our app code clearer:
+
+```js
+const MARKS = {
+ bold: {
+ fontWeight: 'bold'
+ },
+ code: {
+ fontFamily: 'monospace'
+ },
+ italic: {
+ fontStyle: 'italic'
+ },
+ strikethrough: {
+ textDecoration: 'strikethrough'
+ },
+ underline: {
+ textDecoration: 'underline'
+ }
+}
+
+// Use the much clearer key names instead of key codes!
+const plugins = [
+ MarkHotkey({ key: 'b', type: 'bold' }),
+ MarkHotkey({ key: '`', type: 'code' }),
+ MarkHotkey({ key: 'i', type: 'italic' }),
+ MarkHotkey({ key: 'd', type: 'strikethrough' }),
+ MarkHotkey({ key: 'u', type: 'underline' })
+]
+
+class App extends React.Component {
+
+ constructor(props) {
+ super(props)
+ this.state = {
+ state: initialState
+ }
+ }
+
+ render() {
+ return (
+ this.renderMark(mark)}
+ renderNode={node => this.renderNode(node)}
+ onChange={state => this.onChange(state)}
+ />
+ )
+ }
+
+ renderMark(mark) {
+ return MARKS[mark.type]
+ }
+
+ renderNode(node) {
+ if (node.type == 'paragraph') return ParagraphNode
+ }
+
+ onChange(state) {
+ this.setState({ state })
+ }
+
+}
+```
+
+That's why plugins are awesome. They let you get really expressive while also making your codebase easier to manage. And since Slate is built with plugins as a primary consideration, using them is dead simple.