# Composable Plugins In the previous section, we showed you how to create a plugin from scratch. Luckily, you don't need to do that in most cases. Milkdown provides a lot of helpers in [@milkdown/utils](/docs/api/utils) to make it easier to create plugins. The **composable** here means that you can use the plugin in other plugins. For example, you can use a command plugin in a keymap plugin. This is a very common pattern in Milkdown. I'll show you some examples of how to use composable plugins. But I won't go into detail about the options and the usage of each plugin. You can find the details in the [API reference](/docs/api/utils#composable). ## Schema The schema plugin is the most important plugin in Milkdown. It defines the structure of the document. A schema plugin in milkdown is a super set of the [node schema spec](https://prosemirror.net/docs/ref/#model.NodeSpec) or [mark schema spec](https://prosemirror.net/docs/ref/#model.MarkSpec) in ProseMirror. Let's create a simple blockquote node plugin as an example: ```typescript import { $node } from "@milkdown/kit/utils"; const blockquote = $node("blockquote", () => ({ content: "block+", group: "block", defining: true, parseDOM: [{ tag: "blockquote" }], toDOM: (node) => ["blockquote", ctx.get(blockquoteAttr.key)(node), 0], parseMarkdown: { match: ({ type }) => type === "blockquote", runner: (state, node, type) => { state.openNode(type).next(node.children).closeNode(); }, }, toMarkdown: { match: (node) => node.type.name === "blockquote", runner: (state, node) => { state.openNode("blockquote").next(node.content).closeNode(); }, }, })); ``` ## Input Rule Since we have a blockquote node, we can create an input rule plugin to make it easier to create a blockquote node. We expect that when we type `> ` at the beginning of a line, the blockquote node will be created. ```typescript import { wrappingInputRule } from "@milkdown/kit/prose/inputrules"; import { $inputRule } from "@milkdown/kit/utils"; export const wrapInBlockquoteInputRule = $inputRule(() => wrappingInputRule(/^\s*>\s$/, blockquoteSchema.type()), ); ``` ## Command We can also create a command plugin to create a blockquote node. The command is useful when we want to create a button to create a blockquote node. ```typescript import { wrapIn } from "@milkdown/kit/prose/commands"; import { $command } from "@milkdown/kit/utils"; export const wrapInBlockquoteCommand = $command( "WrapInBlockquote", () => () => wrapIn(blockquoteSchema.type()), ); ``` ## Shortcut We can also create a shortcut plugin for blockquote. Here we use `Ctrl + Shift + B` as the shortcut. When we press this shortcut, the blockquote node will be created. And we can also use the command we created in the previous section. ```typescript import { commandsCtx } from "@milkdown/kit/core"; import { $useKeymap } from "@milkdown/kit/utils"; export const blockquoteKeymap = $useKeymap("blockquoteKeymap", { WrapInBlockquote: { shortcuts: "Mod-Shift-b", command: (ctx) => { const commands = ctx.get(commandsCtx); return () => commands.call(wrapInBlockquoteCommand.key); }, }, }); ```