Input rules allow you to automatically modify content when specific patterns are typed in the editor. They’re perfect for creating shortcuts like converting **text** to bold or # to a heading.
Overview
ProseKit provides several types of input rules:
Mark Input Rules : Apply inline marks when patterns are typed
Text Block Input Rules : Convert text blocks to different node types
Wrapping Input Rules : Wrap text blocks in container nodes
Custom Input Rules : Define fully custom input rule behavior
Apply inline marks like bold, italic, or code when specific patterns are typed.
Basic Usage
import { defineMarkInputRule } from '@prosekit/extensions/input-rule'
const extension = defineMarkInputRule ({
regex: / \*\* ( [ ^ \s* ] | [ ^ \s* ][ ^ * ] * [ ^ \s* ] ) \*\* $ / ,
type: 'bold' ,
})
With Dynamic Attributes
import { defineMarkInputRule } from '@prosekit/extensions/input-rule'
const extension = defineMarkInputRule ({
regex: /~ ( [ ^ ~ ] + ) ~ $ / ,
type: 'highlight' ,
attrs : ( match ) => {
// Extract color from pattern like ~text:yellow~
const parts = match [ 1 ]. split ( ':' )
return { color: parts [ 1 ] || 'yellow' }
},
})
API Reference
The regular expression to match against. Should end with $ and contain exactly one capture group. Text outside the capture group will be deleted.
type
string | MarkType
required
The mark type to apply to the matched text.
attrs
Attrs | null | ((match: RegExpMatchArray) => Attrs | null)
Attributes to set on the mark. Can be a static object or a function that receives the regex match.
Whether this rule should fire inside code marks.
Text Block Input Rules
Convert text blocks to different node types, like converting lines starting with # to headings.
Basic Usage
import { defineTextBlockInputRule } from '@prosekit/extensions/input-rule'
const extension = defineTextBlockInputRule ({
regex: / ^ ( # {1,6} ) \s $ / ,
type: 'heading' ,
attrs : ( match ) => ({
level: match [ 1 ]. length ,
}),
})
API Reference
The regular expression to match against. Should end with $ and typically start with ^ to match only at the start of a text block.
type
string | NodeType
required
The node type to replace the matched text with.
attrs
Attrs | null | ((match: RegExpMatchArray) => Attrs | null)
Attributes to set on the node.
Wrap text blocks in container nodes, like wrapping lines starting with > in blockquotes.
Basic Usage
import { defineWrappingInputRule } from '@prosekit/extensions/input-rule'
const extension = defineWrappingInputRule ({
regex: / ^ > \s $ / ,
type: 'blockquote' ,
})
With Join Predicate
import { defineWrappingInputRule } from '@prosekit/extensions/input-rule'
const extension = defineWrappingInputRule ({
regex: / ^ - \s $ / ,
type: 'bulletList' ,
join : ( match , node ) => {
// Only join if the previous node is also a bullet list
return node . type . name === 'bulletList'
},
})
API Reference
The regular expression to match against. Should end with $ and typically start with ^.
type
string | NodeType
required
The type of node to wrap in.
attrs
Attrs | null | ((match: RegExpMatchArray) => Attrs | null)
Attributes to set on the wrapping node.
join
(match: RegExpMatchArray, node: ProseMirrorNode) => boolean
Predicate function that controls whether to join with a similar node above. Receives the regex match and the node before the wrapped node.
For complete control, define a custom ProseMirror input rule.
import { defineInputRule } from '@prosekit/extensions/input-rule'
import { InputRule } from '@prosekit/pm/inputrules'
const customRule = new InputRule (
/-- $ / ,
( state , match , start , end ) => {
const tr = state . tr
tr . insertText ( '—' , start , end )
return tr
}
)
const extension = defineInputRule ( customRule )
Real-World Examples
import { defineMarkInputRule , defineTextBlockInputRule , defineWrappingInputRule } from '@prosekit/extensions/input-rule'
import { union } from '@prosekit/core'
const markdownExtension = union ([
// Bold: **text**
defineMarkInputRule ({
regex: / \*\* ( [ ^ \s* ] | [ ^ \s* ][ ^ * ] * [ ^ \s* ] ) \*\* $ / ,
type: 'bold' ,
}),
// Italic: *text*
defineMarkInputRule ({
regex: / \* ( [ ^ \s* ] | [ ^ \s* ][ ^ * ] * [ ^ \s* ] ) \* $ / ,
type: 'italic' ,
}),
// Code: `code`
defineMarkInputRule ({
regex: /` ( [ ^ ` ] + ) ` $ / ,
type: 'code' ,
}),
// Headings: # to ######
defineTextBlockInputRule ({
regex: / ^ ( # {1,6} ) \s $ / ,
type: 'heading' ,
attrs : ( match ) => ({ level: match [ 1 ]. length }),
}),
// Blockquote: > text
defineWrappingInputRule ({
regex: / ^ > \s $ / ,
type: 'blockquote' ,
}),
// Horizontal rule: ---
defineTextBlockInputRule ({
regex: / ^ --- $ / ,
type: 'horizontalRule' ,
}),
])
Auto-Linking
import { defineMarkInputRule } from '@prosekit/extensions/input-rule'
const autoLinkExtension = defineMarkInputRule ({
regex: / ( https ? : \/\/ [ ^ \s ] + ) $ / ,
type: 'link' ,
attrs : ( match ) => ({
href: match [ 1 ],
}),
})
Use Cases
Markdown Shortcuts Convert markdown syntax to formatted text as users type.
Smart Quotes Automatically convert straight quotes to curly quotes.
Auto-Linking Turn URLs into clickable links automatically.
Emoji Shortcuts Convert text shortcuts like :) to emoji.
Tips
Make sure your regex patterns end with $ to match at the end of the typed text. For text block rules, start with ^ to match at the beginning.
Be careful with overlapping patterns. If multiple input rules match the same text, only the first one will fire.