Horizontal Rule adds a void horizontalRule block for separating sections. The package owns the element type, HTML parser, default <hr> render tag, and Markdown-style input rules. The registry kit adds the Plate UI divider component, static renderer, and insert toolbar item.
BasicBlocksKit installs HorizontalRulePlugin with the registry HrElement and both default input rules.
'use client';
import {
BlockquoteRules,
HeadingRules,
HorizontalRuleRules,
} from '@platejs/basic-nodes';
import {
BlockquotePlugin,
HeadingPlugin,
HorizontalRulePlugin,
} from '@platejs/basic-nodes/react';
import { ParagraphPlugin } from 'platejs/react';
import { BlockquoteElement } from '@/components/editor/blockquote';
import { HeadingElement } from '@/components/editor/heading';
import { HrElement } from '@/components/editor/horizontal-rule';
import { ParagraphElement } from '@/components/editor/paragraph';
export const BasicBlocksKit = [
ParagraphPlugin.configure({ component: ParagraphElement }),
HeadingPlugin.configure({
component: HeadingElement,
inputRules: [HeadingRules.markdown()],
rules: {
break: { empty: 'reset' },
},
shortcuts: {
toggleHeading1: {
handler: ({ editor }) => {
editor.plugin(HeadingPlugin).update.toggle({ level: 1 });
},
keys: 'mod+alt+1',
},
toggleHeading2: {
handler: ({ editor }) => {
editor.plugin(HeadingPlugin).update.toggle({ level: 2 });
},
keys: 'mod+alt+2',
},
toggleHeading3: {
handler: ({ editor }) => {
editor.plugin(HeadingPlugin).update.toggle({ level: 3 });
},
keys: 'mod+alt+3',
},
toggleHeading4: {
handler: ({ editor }) => {
editor.plugin(HeadingPlugin).update.toggle({ level: 4 });
},
keys: 'mod+alt+4',
},
toggleHeading5: {
handler: ({ editor }) => {
editor.plugin(HeadingPlugin).update.toggle({ level: 5 });
},
keys: 'mod+alt+5',
},
toggleHeading6: {
handler: ({ editor }) => {
editor.plugin(HeadingPlugin).update.toggle({ level: 6 });
},
keys: 'mod+alt+6',
},
},
}),
BlockquotePlugin.configure({
component: BlockquoteElement,
inputRules: [BlockquoteRules.markdown()],
shortcuts: { toggle: { keys: 'mod+shift+period' } },
}),
HorizontalRulePlugin.configure({
component: HrElement,
inputRules: [
HorizontalRuleRules.markdown({ variant: '-' }),
HorizontalRuleRules.markdown({ variant: '_' }),
],
}),
] as const;'use client';
import {
BlockquoteRules,
HeadingRules,
HorizontalRuleRules,
} from '@platejs/basic-nodes';
import {
BlockquotePlugin,
HeadingPlugin,
HorizontalRulePlugin,
} from '@platejs/basic-nodes/react';
import { ParagraphPlugin } from 'platejs/react';
import { BlockquoteElement } from '@/components/editor/blockquote';
import { HeadingElement } from '@/components/editor/heading';
import { HrElement } from '@/components/editor/horizontal-rule';
import { ParagraphElement } from '@/components/editor/paragraph';
import { createPlateEditor } from 'platejs/react';
import { BasicBlocksKit } from '@/components/editor/basic-blocks';
export const editor = createPlateEditor({
plugins: BasicBlocksKit,
});import { createPlateEditor } from 'platejs/react';
import { BasicBlocksKit } from '@/components/editor/basic-blocks';
export const editor = createPlateEditor({
plugins: BasicBlocksKit,
horizontal-rule renders the editable divider with selected/focused ring styles and a static companion component.
'use client';
import type { HorizontalRulePlugin } from '@platejs/basic-nodes/react';
import type { PlateElementProps } from 'platejs/react';
import {
PlateElement,
useEditorFocused,
useEditorReadOnly,
useElementSelected,
} from 'platejs/react';
import * as React from 'react';
import { cn } from '@/lib/utils';
export function HrElement(
props: PlateElementProps<typeof HorizontalRulePlugin>
) {
const readOnly
Use BaseBasicBlocksKit when rendering read-only content with platejs/static.
import {
BaseBlockquotePlugin,
BaseHeadingPlugin,
BaseHorizontalRulePlugin,
} from '@platejs/basic-nodes';
import { BaseParagraphPlugin } from 'platejs';
import { BlockquoteElementStatic } from '@/components/editor/blockquote-static';
import { HeadingElementStatic } from '@/components/editor/heading-static';
import { HrElementStatic } from '@/components/editor/horizontal-rule-static';
import { ParagraphElementStatic } from '@/components/editor/paragraph-static';
export const BaseBasicBlocksKit = [
BaseParagraphPlugin.configure({
component: ParagraphElementStatic,
}),
BaseHeadingPlugin.
| Layer | Owner | What It Does |
|---|---|---|
@platejs/basic-nodes | Package | Exports BaseHorizontalRulePlugin and HorizontalRuleRules. |
@platejs/basic-nodes/react | Package | Exports HorizontalRulePlugin. |
basic-blocks | Registry | Adds HorizontalRulePlugin with dash and underscore input rules plus HrElement. |
basic-blocks-static | Registry | Adds BaseHorizontalRulePlugin.configure({ component: HrElementStatic }). |
horizontal-rule | Registry UI | Renders editable and static divider components. |
| Insert toolbar | Registry UI | Uses PLUGINS.horizontalRule to select the horizontal-rule capability, then inserts its resolved schema type through the generic insertBlock path. |
There is no package-specific insertHorizontalRule helper. App UI usually passes PLUGINS.horizontalRule to the same descriptor-aware block insertion helper used by other registry blocks.
Use the React plugin when the editor renders the divider UI.
import { HorizontalRuleRules } from '@platejs/basic-nodes';
import { HorizontalRulePlugin } from '@platejs/basic-nodes/react';
import { createPlateEditor } from 'platejs/react';
import { HrElement } from '@/components/editor/horizontal-rule';
export const editor = createPlateEditor({
plugins: [
HorizontalRulePlugin.configure({
component: HrElement,
inputRules: [
HorizontalRuleRules.markdown({ variant: '-' }),
HorizontalRuleRules.markdown({ variant: '_' }),
],
}),
],
});import { HorizontalRuleRules } from '@platejs/basic-nodes';
import { HorizontalRulePlugin } from '@platejs/basic-nodes/react';
import { createPlateEditor } from 'platejs/react';
import { HrElement } from '@/components/editor/horizontal-rule';
export const editor = createPlateEditor({
plugins: [
HorizontalRulePlugin.configure({
component: HrElement,
inputRules: [
HorizontalRuleRules.markdown({ variant: '-' }),
HorizontalRuleRules.markdown({ variant: '_' }),
],
}),
],
});Use the base plugin with the static component in static rendering paths.
import { BaseHorizontalRulePlugin } from '@platejs/basic-nodes';
import { createStaticEditor } from 'platejs/static';
import { HrElementStatic } from '@/components/editor/horizontal-rule-static';
export const staticEditor = createStaticEditor({
plugins: [
BaseHorizontalRulePlugin.configure({
component: HrElementStatic,
}),
],
});import { BaseHorizontalRulePlugin }
Horizontal rules are void block elements. Keep the empty text child so the node remains a valid Plite element.
const value = [
{
children: [{ text: 'Before the divider' }],
type: 'paragraph',
},
{
children: [{ text: '' }],
type: 'horizontalRule',
},
{
children: [{ text: 'After the divider' }],
type: 'paragraph',
},
];const value = [
{
children: [{ text: 'Before the divider' }],
type: 'paragraph',
},
{
children: [{ text: '' }],
type: 'horizontalRule',
},
{
children: [{ text: 'After the divider' }],
type: 'paragraph',
},
];| Field | Type | Notes |
|---|---|---|
type | 'horizontalRule' | Default persisted element type. Read the resolved type from editor.plugin(BaseHorizontalRulePlugin).schema.type in reusable code. |
children | [{ text: '' }] | Required child for the void element. |
HorizontalRuleRules.markdown() converts a paragraph into a horizontalRule block and inserts an empty paragraph after it.
| Rule | Trigger | Behavior |
|---|---|---|
HorizontalRuleRules.markdown({ variant: '-' }) | type the third - after -- | Converts --- to horizontalRule, then inserts a paragraph. |
HorizontalRuleRules.markdown({ variant: '_' }) | type a space after ___ | Converts ___ to horizontalRule, then inserts a paragraph. |
The rule resolves BaseHorizontalRulePlugin through the editor and passes its schema.type to tx.nodes.set, so configured element types keep working.
| Surface | Behavior |
|---|---|
| Editable element | Renders a non-editable padded wrapper with an <hr> inside it. |
| Selected + focused | Adds a focus ring around the divider. |
| Read-only | Removes the pointer cursor from the editable component. |
| Static element | Renders the same divider inside PliteElement. |
| Insert toolbar | Adds a Divider item with MinusIcon; PLUGINS.horizontalRule selects the capability. |
The divider component renders {props.children} after the non-editable wrapper so Plite can still keep the void child mounted.
| API | Package | Use |
|---|---|---|
BaseHorizontalRulePlugin | @platejs/basic-nodes | Headless void horizontalRule block with HTML deserialization and default render tag. |
HorizontalRulePlugin | @platejs/basic-nodes/react | React horizontal rule plugin. |
HorizontalRuleRules.markdown({ variant: '-' }) | @platejs/basic-nodes | Creates the dash input rule for ---. |
HorizontalRuleRules.markdown({ variant: '_' }) | @platejs/basic-nodes | Creates the underscore input rule for ___ . |
'use client';
import type { HorizontalRulePlugin } from '@platejs/basic-nodes/react';
import type { PlateElementProps } from 'platejs/react';
import {
PlateElement,
useEditorFocused,
useEditorReadOnly,
useElementSelected,
} from 'platejs/react';
import * as React from 'react';
import { cn } from '@/lib/utils';
export function HrElement(
props: PlateElementProps<typeof HorizontalRulePlugin>
) {
const readOnly = useEditorReadOnly();
const selected = useElementSelected();
const focused = useEditorFocused();
return (
<PlateElement {...props}>
<div className="py-6" contentEditable={false}>
<hr
className={cn(
'h-0.5 rounded-sm border-none bg-muted bg-clip-content',
selected && focused && 'ring-2 ring-ring ring-offset-2',
!readOnly && 'cursor-pointer'
)}
/>
</div>
{props.children}
</PlateElement>
);
}import {
BaseBlockquotePlugin,
BaseHeadingPlugin,
BaseHorizontalRulePlugin,
} from '@platejs/basic-nodes';
import { BaseParagraphPlugin } from 'platejs';
import { BlockquoteElementStatic } from '@/components/editor/blockquote-static';
import { HeadingElementStatic } from '@/components/editor/heading-static';
import { HrElementStatic } from '@/components/editor/horizontal-rule-static';
import { ParagraphElementStatic } from '@/components/editor/paragraph-static';
export const BaseBasicBlocksKit = [
BaseParagraphPlugin.configure({
component: ParagraphElementStatic,
}),
BaseHeadingPlugin.configure({ component: HeadingElementStatic }),
BaseBlockquotePlugin.configure({
component: BlockquoteElementStatic,
}),
BaseHorizontalRulePlugin.configure({
component: HrElementStatic,
}),
];