From zbeyens. The source code is available on GitHub.

Plate
PlatePliteEditorsTemplates
GitHub16kGitHub
DiscordDiscord
    • Stream
    • Copilot
  • Discussion
    • Comments
    • Suggestion
    • Basic Blocks
      • Blockquote
      • Heading
      • Horizontal Rule
    • Callout
    • Code Block
    • Column
    • Date
    • Equation
    • Link
    • List Classic
    • Media
    • MentionElement
    • Table
    • Table of Contents
    • Footnote
    • Toggle
  • Marks
    • Bold
    • Italic
    • Underline
    • Code
    • Highlight
    • Keyboard Input
    • Strikethrough
    • Subscript
    • Superscript
      • Font
      • Line Height
      • Text Align
    • Indent
    • List
      • Exit Break
      • Single Block
      • Trailing Block
    • Autoformat
    • Block Menu
    • Block Placeholder
    • Combobox
      • Emoji
      • MentionElement
      • Slash Command
    • Cursor Overlay
    • Drag & Drop
    • Navigation Feedback
    • Tabbable
    • Toolbar
    • Yjs
    • Multi SelectEditor
    • CSV
    • DOCX
    • HTML
    • Markdown

Keyboard Input

PreviousNext

Style keyboard shortcuts and key names.

Basic MarksKeyboard Input LeafMore Toolbar Button

Keyboard Input applies the kbd leaf mark to selected text. Use it for shortcuts, key names, and command hints that should render as <kbd>.

Loading…
HighlightStrikethrough

On This Page

FeaturesKit UsageAdd Basic MarksAdd the LeafAdd a Toolbar ControlManual UsageOwnershipBehaviorAPI Reference
Build your editor
Production-ready AI template and reusable components.
Get all-access

Features

  • Boolean kbd leaf property owned by the PLUGINS.kbd capability.
  • Hard selection affinity.
  • HTML deserialization from kbd.
  • <kbd> rendering by default.
  • Registry KbdLeaf for styled keyboard input.
  • Static rendering support through KbdLeafStatic.
Report an issue

Kit Usage

Add Basic Marks

BasicMarksKit includes KbdPlugin.configure({ component: KbdLeaf }). It does not add a shortcut or input rule for keyboard input.

'use client';
 
import {
  BoldRules,
  CodeRules,
  HighlightRules,
  ItalicRules,
  MarkComboRules,
  ScriptRules,
  StrikethroughRules,
  UnderlineRules,
} from '@platejs/basic-nodes';
import {
  BoldPlugin,
  CodePlugin,
  HighlightPlugin,
  ItalicPlugin,
  KbdPlugin,
  ScriptPlugin,
  StrikethroughPlugin,
  UnderlinePlugin,
} from '@platejs/basic-nodes/react';
 
import { CodeLeaf } from '@/components/editor/code';
import { HighlightLeaf } from '@/components/editor/highlight';
import { KbdLeaf } from '@/components/editor/kbd';
 
export const BasicMarksKit = [
  BoldPlugin.configure({
    inputRules: [
      BoldRules.markdown({ variant: '*' }),
      BoldRules.markdown({ variant: '_' }),
      MarkComboRules.markdown({ variant: 'boldItalic' }),
      MarkComboRules.markdown({ variant: 'boldUnderline' }),
      MarkComboRules.markdown({ variant: 'boldItalicUnderline' }),
      MarkComboRules.markdown({ variant: 'italicUnderline' }),
    ],
  }),
  ItalicPlugin.configure({
    inputRules: [
      ItalicRules.markdown({ variant: '*' }),
      ItalicRules.markdown({ variant: '_' }),
    ],
  }),
  UnderlinePlugin.configure({
    inputRules: [UnderlineRules.markdown()],
  }),
  CodePlugin.configure({
    component: CodeLeaf,
    inputRules: [CodeRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+e' } },
  }),
  StrikethroughPlugin.configure({
    inputRules: [StrikethroughRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+shift+x' } },
  }),
  ScriptPlugin.configure({
    inputRules: [
      ScriptRules.markdown({ value: 'sub' }),
      ScriptRules.markdown({ value: 'sup' }),
    ],
    shortcuts: {
      subscript: {
        keys: 'mod+comma',
        handler: ({ editor }) => {
          editor.plugin(ScriptPlugin).update.toggle('sub');
        },
      },
      superscript: {
        keys: 'mod+period',
        handler: ({ editor }) => {
          editor.plugin(ScriptPlugin).update.toggle('sup');
        },
      },
    },
  }),
  HighlightPlugin.configure({
    component: HighlightLeaf,
    inputRules: [
      HighlightRules.markdown({ variant: '==' }),
      HighlightRules.markdown({ variant: '≡' }),
    ],
    shortcuts: { toggle: { keys: 'mod+shift+h' } },
  }),
  KbdPlugin.configure({ component: KbdLeaf }),
] as const;
'use client';
 
import {
  BoldRules,
  CodeRules,
  HighlightRules,
  ItalicRules,
  MarkComboRules,
  ScriptRules,
  StrikethroughRules,
  UnderlineRules,
} from '@platejs/basic-nodes';
import {
  BoldPlugin,
  CodePlugin,
  HighlightPlugin,
  ItalicPlugin,
  KbdPlugin,
  ScriptPlugin,
  StrikethroughPlugin,
  UnderlinePlugin,
} from '@platejs/basic-nodes/react';
 
import { CodeLeaf } from '@/components/editor/code';
import { HighlightLeaf } from '@/components/editor/highlight';




























































import { createPlateEditor } from 'platejs/react';
 
import { BasicMarksKit } from '@/components/editor/basic-marks';
 
export const editor = createPlateEditor({
  plugins: [...BasicMarksKit],
});
import { createPlateEditor } from 'platejs/react';
 
import { BasicMarksKit } from '@/components/editor/basic-marks';
 
export const editor = createPlateEditor({

Add the Leaf

KbdLeaf provides the registry styling for the <kbd> element.

'use client';
 
import type { KbdPlugin } from '@platejs/basic-nodes/react';
import type { PlateLeafProps } from 'platejs/react';
import { PlateLeaf } from 'platejs/react';
import * as React from 'react';
 
export function KbdLeaf(props: PlateLeafProps<typeof KbdPlugin>) {
  return (
    <PlateLeaf
      {...props}
      as="kbd"
      className="rounded border border-border bg-muted px-1.5 py-0.5 font-mono text-sm shadow-[rgba(255,_255,_255,_0.1)_0px_0.5px_0px_0px_inset,_rgb(248,_249,_250)_0px_1px_5px_0px_inset,_rgb(193,_200,_205)_0px_0px_0px_0.5px,_rgb(193,_200,_205)_0px_2px_1px_-1px,_rgb(193,_200,_205)_0px_1px_0px_0px] dark:shadow-[rgba(255,_255,_255,_0.1)_0px_0.5px_0px_0px_inset,_rgb(26,_29,_30)_0px_1px_5px_0px_inset,_rgb(76,_81,_85)_0px_0px_0px_0.5px,_rgb(76,_81,_85)_0px_2px_1px_-1px,_rgb(76,_81,_85)_0px_1px_0px_0px]"




Add a Toolbar Control

The registry MoreToolbarButton toggles keyboard input from the More menu.

import { MoreToolbarButton } from '@/components/editor/more-toolbar-button';
 
export function FormattingMoreMenu() {
  return <MoreToolbarButton />;
}
import { MoreToolbarButton } from '@/components/editor/more-toolbar-button';
 
export function FormattingMoreMenu() {
  return <MoreToolbarButton />;
}

Manual Usage

Install the mark package.

pnpm add @platejs/basic-nodes
pnpm add @platejs/basic-nodes

Add KbdPlugin directly when you want the default <kbd> render.

import { KbdPlugin } from '@platejs/basic-nodes/react';
import { createPlateEditor } from 'platejs/react';
 
export const editor = createPlateEditor({
  plugins: [KbdPlugin],
});
import { KbdPlugin } from '@platejs/basic-nodes/react';
import { createPlateEditor } from 'platejs/react';
 
export const editor = createPlateEditor({
  plugins: [KbdPlugin],
});

Attach the registry leaf when you want the same visual treatment as the kit.

import { KbdPlugin } from '@platejs/basic-nodes/react';
 
import { KbdLeaf } from '@/components/editor/kbd';
 
export const kbdPlugin = KbdPlugin.configure({ component: KbdLeaf });
import { KbdPlugin } from '@platejs/basic-nodes/react';
 
import { KbdLeaf } from '@/components/editor/kbd';
 
export const kbdPlugin = KbdPlugin.configure({ component: KbdLeaf });

Ownership

SurfaceOwnerWhat It Does
BaseKbdPlugin@platejs/basic-nodesHeadless keyboard-input mark, HTML parser, render tag, selection rule, and toggle transform.
KbdPlugin@platejs/basic-nodes/reactReact wrapper for the headless keyboard-input mark.
KbdLeafRegistry UIStyled client <kbd> leaf using PlateLeaf.
KbdLeafStaticRegistry UIStatic rendering version using PliteLeaf.
BasicMarksKitRegistryAdds KbdPlugin.configure({ component: KbdLeaf }).
MoreToolbarButtonRegistry UICalls editor.plugin(KbdPlugin).update.toggle() from the More menu.

The package owns the mark. The registry owns keycap styling and toolbar placement.

Behavior

BehaviorSource
Mark keyeditor.plugin(KbdPlugin).schema.key (default: kbd)
Mark declarationschema.mark: property.boolean({ default: false, omitDefault: true })
Toggle commandtx.kbd.toggle() toggles the resolved schema key.
Selection affinityhard
HTML tagskbd
Render outputkbd
Kit componentKbdLeaf
Registry toolbarMoreToolbarButton toggles through KbdPlugin.

API Reference

APIPackageUse
BaseKbdPlugin@platejs/basic-nodesHeadless keyboard-input plugin.
KbdPlugin@platejs/basic-nodes/reactReact keyboard-input plugin.
tx.kbd.toggle()@platejs/basic-nodesToggles the keyboard-input mark at the selection.
KbdLeafRegistry UIStyled client keyboard-input leaf.
KbdLeafStaticRegistry UIStyled static keyboard-input leaf.
import { KbdLeaf } from '@/components/editor/kbd';
export const BasicMarksKit = [
BoldPlugin.configure({
inputRules: [
BoldRules.markdown({ variant: '*' }),
BoldRules.markdown({ variant: '_' }),
MarkComboRules.markdown({ variant: 'boldItalic' }),
MarkComboRules.markdown({ variant: 'boldUnderline' }),
MarkComboRules.markdown({ variant: 'boldItalicUnderline' }),
MarkComboRules.markdown({ variant: 'italicUnderline' }),
],
}),
ItalicPlugin.configure({
inputRules: [
ItalicRules.markdown({ variant: '*' }),
ItalicRules.markdown({ variant: '_' }),
],
}),
UnderlinePlugin.configure({
inputRules: [UnderlineRules.markdown()],
}),
CodePlugin.configure({
component: CodeLeaf,
inputRules: [CodeRules.markdown()],
shortcuts: { toggle: { keys: 'mod+e' } },
}),
StrikethroughPlugin.configure({
inputRules: [StrikethroughRules.markdown()],
shortcuts: { toggle: { keys: 'mod+shift+x' } },
}),
ScriptPlugin.configure({
inputRules: [
ScriptRules.markdown({ value: 'sub' }),
ScriptRules.markdown({ value: 'sup' }),
],
shortcuts: {
subscript: {
keys: 'mod+comma',
handler: ({ editor }) => {
editor.plugin(ScriptPlugin).update.toggle('sub');
},
},
superscript: {
keys: 'mod+period',
handler: ({ editor }) => {
editor.plugin(ScriptPlugin).update.toggle('sup');
},
},
},
}),
HighlightPlugin.configure({
component: HighlightLeaf,
inputRules: [
HighlightRules.markdown({ variant: '==' }),
HighlightRules.markdown({ variant: '≡' }),
],
shortcuts: { toggle: { keys: 'mod+shift+h' } },
}),
KbdPlugin.configure({ component: KbdLeaf }),
] as const;
plugins: [
...
BasicMarksKit],
});
>
{props.children}
</PlateLeaf>
);
}
'use client';
 
import type { KbdPlugin } from '@platejs/basic-nodes/react';
import type { PlateLeafProps } from 'platejs/react';
import { PlateLeaf } from 'platejs/react';
import * as React from 'react';
 
export function KbdLeaf(props: PlateLeafProps<typeof KbdPlugin>) {
  return (
    <PlateLeaf
      {...props}
      as="kbd"
      className="rounded border border-border bg-muted px-1.5 py-0.5 font-mono text-sm shadow-[rgba(255,_255,_255,_0.1)_0px_0.5px_0px_0px_inset,_rgb(248,_249,_250)_0px_1px_5px_0px_inset,_rgb(193,_200,_205)_0px_0px_0px_0.5px,_rgb(193,_200,_205)_0px_2px_1px_-1px,_rgb(193,_200,_205)_0px_1px_0px_0px] dark:shadow-[rgba(255,_255,_255,_0.1)_0px_0.5px_0px_0px_inset,_rgb(26,_29,_30)_0px_1px_5px_0px_inset,_rgb(76,_81,_85)_0px_0px_0px_0.5px,_rgb(76,_81,_85)_0px_2px_1px_-1px,_rgb(76,_81,_85)_0px_1px_0px_0px]"
    >
      {props.children}
    </PlateLeaf>
  );
}