docs/plans/2026-04-15-input-rules-plugin-api-doc-plan.md
Proposed.
Create a new canonical guide at content/(guides)/plugin-input-rules.mdx for the Input Rules runtime and API.
This guide should replace the current canonical role of content/(plugins)/(functionality)/autoformat.mdx without pretending that "autoformat" is the right top-level concept.
The new guide should teach the actual system:
InputRulesPlugin runtimeThe result should become the canonical user-facing reference for how input rules work in Plate today.
The current docs have a real naming conflict:
autoformat.mdx page is trying to explain the input-rule runtime
under the wrong nameThat is why a brand-new guide path is better than squeezing this into either existing page.
The current autoformat.mdx page is also no longer the right abstraction.
Today it mixes multiple different lanes under one old label:
@platejs/basic-nodes, @platejs/code-block, @platejs/list,
@platejs/link, and @platejs/mathdefineInputRule(...)That made sense when "autoformat" was the broad mental model. It does not match the current architecture anymore.
Current law is now:
So the docs should teach Input Rules as the system and treat AutoformatKit
as one example of local copied rule code, not the conceptual center.
Use Plugin Input Rules as the page title.
Do not title the public page:
InputRulesPluginInput RulesWhy:
InputRulesPlugin is too internalInput Rules is semantically right but too collision-prone next to
Plugin RulesPlugin Input Rules is explicit in nav and avoids the sibling-guide naming
clashCreate a new guide path:
Why:
/docs/plugin-input-rulesautoformat route with the wrong mental
modelFollow-up handling for the old page:
Create the Chinese twin in the guide lane:
Then decide whether the old CN autoformat page becomes narrow or becomes a pointer page in lockstep with the English version.
This doc has three real audiences:
They want to:
They want to:
'*' vs '_'on: 'match' | 'break'enabledpriorityThey want to:
createMarkInputRule, createBlockStartInputRule,
createBlockFenceInputRule, createTextSubstitutionInputRuleinputRules: ({ rule }) => [...]The page should serve all three without turning the opening into a wall of internal types.
This page should not:
inputRulesdefineInputRule(...) examples firstThe new guide should teach one sentence clearly:
Input rules are the shared runtime for typed editor conversions in Plate. Feature packages export semantic rule families, kits register explicit rule instances, and local copied shortcuts stay local.
Everything on the page should reinforce that.
Recommended frontmatter direction:
---
title: Plugin Input Rules
description: Typed editor rules for markdown shortcuts, block fences, autolinks, and local text substitutions.
docs:
- route: /docs/basic-blocks
title: Basic Elements
- route: /docs/basic-marks
title: Basic Marks
- route: /docs/code-block
title: Code Block
- route: /docs/link
title: Link
- route: /docs/list
title: List
- route: /docs/equation
title: Equation
---
Open with a direct explanation of what the page is for:
Do not open by centering AutoformatKit or by comparing yourself to
plugin-rules defensively. Just teach the system.
## What Plugin Input Rules Are## Quick Start## Feature-Owned Markdown Rules## Local Copied Shortcuts## Custom Rules## How Rule Execution Works## API ReferenceThat order is deliberate:
## What Plugin Input Rules ArePurpose:
Plugin Rules immediatelyRequired content:
plugin-rules controls node behavior policyplugin-input-rules controls typed conversion behavior| Lane | Owner | Example |
|---|---|---|
| feature markdown rule | package | HeadingRules.markdown() |
| feature interaction rule | package | LinkRules.autolink({ variant: 'space' }) |
| local substitutions | app/local kit | createTextSubstitutionInputRule(...) |
| raw custom rule | app or package | defineInputRule(...) |
Callout to include:
## Quick StartPurpose:
Required content:
AutoformatKit, but only as the quick path for common local text
substitutionsAutoformatKit is the only or main pathRecommended substeps:
### Add Local Text SubstitutionsUse:
Explain:
@platejs/autoformat package contract### Add Feature-Owned Markdown RulesUse a compact createPlateEditor example with:
Important:
on for block-fence familieson in the examples## Feature-Owned Markdown RulesPurpose:
This should be the biggest section in the tutorial half of the guide.
Recommended subsection order:
### Basic BlocksUse:
HeadingRules.markdown()BlockquoteRules.markdown()HorizontalRuleRules.markdown({ variant: '-' | '_' })Explain:
enabled for code-block gating### Basic MarksUse:
BoldRules.markdown({ variant: '*' | '_' })ItalicRules.markdown({ variant: '*' | '_' })UnderlineRules.markdown()MarkComboRules.markdown({ variant: ... })Explain:
### Code BlocksUse:
CodeBlockRules.markdown({ on: 'match' })CodeBlockRules.markdown({ on: 'break' })Explain:
on: 'match' means fire when the fence becomes completeon: 'break' means fire on Enter after the fence is completeon is required because those behaviors are meaningfully different### ListsUse:
BulletedListRules.markdown({ variant: '-' })OrderedListRules.markdown({ variant: '.' })TaskListRules.markdown({ checked: false })Explain:
@platejs/listenabled, not matcher hacks### MathUse:
MathRules.markdown({ variant: '$' })MathRules.markdown({ variant: '$$', on: 'break' })Explain:
$...$ and block $$ are intentionally split$$ requires explicit onenabled exists for app overrides when needed### LinksUse:
LinkRules.markdown()LinkRules.autolink({ variant: 'paste' | 'space' | 'break' })Explain:
## Local Copied ShortcutsPurpose:
Recommended flow:
### Use createTextSubstitutionInputRuleUse a compact example based on autoformat-kit.tsx:
enabled gating around code blocksExplain:
### When defineInputRule Is BetterOnly after the helper example:
defineInputRule(...) exampleDo not lead with raw defineInputRule(...).
## Custom RulesPurpose:
Recommended subsections:
### Register Explicit Rule InstancesShow:
Plugin.configure({
inputRules: [
SomeRules.markdown(...),
{ ...LinkRules.autolink({ variant: 'paste' }), priority: 200 },
],
});
Required explanation:
priority is overridden on the returned rule object, not inside package
factory params### Use Plugin-Side FactoriesShow:
createSlatePlugin({
key: 'custom',
inputRules: ({ rule }) => [
rule.mark(...),
rule.blockStart(...),
rule.blockFence(...),
],
});
Explain:
rule.* helpers are sugar over the shared core builders## How Rule Execution WorksPurpose:
Required content:
enabledresolveapplyinsertTextinsertBreakinsertDatagetBlockEntrygetBlockStartRangegetBlockStartTextgetBlockTextBeforeSelectiongetCharBeforegetCharAfterpluginKeyRecommended table:
| Field | Purpose |
|---|---|
enabled | policy gate |
resolve | compute payload |
apply | perform transform |
priority | ordering override |
trigger | typed input dispatch for insertText |
on | block-fence commit mode |
Important note:
match and matcher helpers should own syntax, not policyenabled for gating instead of returning undefined from match just to
suppress a rule## API ReferencePurpose:
Recommended subsections:
### Rule TargetsinsertTextinsertBreakinsertData### Core HelpersdefineInputRulecreateMarkInputRulecreateBlockStartInputRulecreateBlockFenceInputRulecreateTextSubstitutionInputRulematchDelimitedInlineFor each helper, include:
### Package Rule FamiliesList the important shipped families with one-line descriptions:
HeadingRulesBlockquoteRulesHorizontalRuleRulesBoldRulesItalicRulesMarkComboRulesCodeBlockRulesBulletedListRulesOrderedListRulesTaskListRulesMathRulesLinkRulesThe final doc should include these exact example shapes:
AutoformatKiton: 'match'on: 'break'createTextSubstitutionInputRuledefineInputRuleinputRules: ({ rule }) => [...]priority override example using object spreadenabled override exampleinputRulesdefineInputRule(...) as the first customization examplePlugin Rulesenabled as the generic gating laneon semanticsapps/www/public/r/** will refresh from
the app build; do not edit them by handWhen the doc is actually written, verify with:
pnpm turbo build --filter=./apps/wwwpnpm turbo typecheck --filter=./apps/wwwpnpm lint:fixAnd for browser proof:
/docs/plugin-input-rules in a browser/docs/plugin-rulesautoformat page no longer carries the canonical explanationThe replacement is successful when:
plugin-rulesAutoformatKit is demoted to one local example, not the conceptual centerenabled, priority, and block-fence on are all documented clearly## API Reference, not in
the opening tutorial sectionsplugin-input-rules.mdx and plugin-input-rules.cn.mdxplugin-rulesautoformat pageThis guide should become the canonical answer to:
If the result still feels like "an autoformat page with extra notes" or "a shadow copy of plugin-rules", it failed.