Underline

PreviousNext

Add underlined inline text.

Underline applies the underline leaf mark to selected text. UnderlinePlugin owns the mark key, shortcut, HTML parsing, render tag, and toggle transform.

Loading…

Features

  • KEYS.underline leaf mark.
  • Default ⌘U / Ctrl+U shortcut.
  • HTML deserialization from u and underline text decoration.
  • <u> rendering by default.
  • Optional Markdown-style input rule through UnderlineRules.
  • Toolbar support through MarkToolbarButton.

Kit Usage

Add Basic Marks

BasicMarksKit includes UnderlinePlugin, the underscore input rule, and the standard toolbar buttons that use KEYS.underline.

'use client';
 
import {
  BoldRules,
  CodeRules,
  HighlightRules,
  ItalicRules,
  MarkComboRules,
  StrikethroughRules,
  SubscriptRules,
  SuperscriptRules,
  UnderlineRules,
} from '@platejs/basic-nodes';
import {
  BoldPlugin,
  CodePlugin,
  HighlightPlugin,
  ItalicPlugin,
  KbdPlugin,
  StrikethroughPlugin,
  SubscriptPlugin,
  SuperscriptPlugin,
  UnderlinePlugin,
} from '@platejs/basic-nodes/react';
 
import { CodeLeaf } from '@/components/ui/code-node';
import { HighlightLeaf } from '@/components/ui/highlight-node';
import { KbdLeaf } from '@/components/ui/kbd-node';
 
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({
    inputRules: [CodeRules.markdown()],
    node: { component: CodeLeaf },
    shortcuts: { toggle: { keys: 'mod+e' } },
  }),
  StrikethroughPlugin.configure({
    inputRules: [StrikethroughRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+shift+x' } },
  }),
  SubscriptPlugin.configure({
    inputRules: [SubscriptRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+comma' } },
  }),
  SuperscriptPlugin.configure({
    inputRules: [SuperscriptRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+period' } },
  }),
  HighlightPlugin.configure({
    inputRules: [
      HighlightRules.markdown({ variant: '==' }),
      HighlightRules.markdown({ variant: '≡' }),
    ],
    node: { component: HighlightLeaf },
    shortcuts: { toggle: { keys: 'mod+shift+h' } },
  }),
  KbdPlugin.withComponent(KbdLeaf),
];
'use client';
 
import {
  BoldRules,
  CodeRules,
  HighlightRules,
  ItalicRules,
  MarkComboRules,
  StrikethroughRules,
  SubscriptRules,
  SuperscriptRules,
  UnderlineRules,
} from '@platejs/basic-nodes';
import {
  BoldPlugin,
  CodePlugin,
  HighlightPlugin,
  ItalicPlugin,
  KbdPlugin,
  StrikethroughPlugin,
  SubscriptPlugin,
  SuperscriptPlugin,
  UnderlinePlugin,
} from '@platejs/basic-nodes/react';
 
import { CodeLeaf } from '@/components/ui/code-node';
import { HighlightLeaf } from '@/components/ui/highlight-node';
import { KbdLeaf } from '@/components/ui/kbd-node';
 
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({
    inputRules: [CodeRules.markdown()],
    node: { component: CodeLeaf },
    shortcuts: { toggle: { keys: 'mod+e' } },
  }),
  StrikethroughPlugin.configure({
    inputRules: [StrikethroughRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+shift+x' } },
  }),
  SubscriptPlugin.configure({
    inputRules: [SubscriptRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+comma' } },
  }),
  SuperscriptPlugin.configure({
    inputRules: [SuperscriptRules.markdown()],
    shortcuts: { toggle: { keys: 'mod+period' } },
  }),
  HighlightPlugin.configure({
    inputRules: [
      HighlightRules.markdown({ variant: '==' }),
      HighlightRules.markdown({ variant: '≡' }),
    ],
    node: { component: HighlightLeaf },
    shortcuts: { toggle: { keys: 'mod+shift+h' } },
  }),
  KbdPlugin.withComponent(KbdLeaf),
];
import { createPlateEditor } from 'platejs/react';
 
import { BasicMarksKit } from '@/components/editor/plugins/basic-marks-kit';
 
export const editor = createPlateEditor({
  plugins: [...BasicMarksKit],
});
import { createPlateEditor } from 'platejs/react';
 
import { BasicMarksKit } from '@/components/editor/plugins/basic-marks-kit';
 
export const editor = createPlateEditor({
  plugins: [...BasicMarksKit],
});

Add A Toolbar Button

Use MarkToolbarButton with KEYS.underline.

import { UnderlineIcon } from 'lucide-react';
import { KEYS } from 'platejs';
 
import { MarkToolbarButton } from '@/components/ui/mark-toolbar-button';
 
export function UnderlineToolbarButton() {
  return (
    <MarkToolbarButton nodeType={KEYS.underline} tooltip="Underline (⌘+U)">
      <UnderlineIcon />
    </MarkToolbarButton>
  );
}
import { UnderlineIcon } from 'lucide-react';
import { KEYS } from 'platejs';
 
import { MarkToolbarButton } from '@/components/ui/mark-toolbar-button';
 
export function UnderlineToolbarButton() {
  return (
    <MarkToolbarButton nodeType={KEYS.underline} tooltip="Underline (⌘+U)">
      <UnderlineIcon />
    </MarkToolbarButton>
  );
}

Manual Usage

Install the mark package.

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

Add UnderlinePlugin directly when you do not want the whole kit.

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

Register the Markdown-style input rule when users should type underline delimiters.

import { UnderlineRules } from '@platejs/basic-nodes';
import { UnderlinePlugin } from '@platejs/basic-nodes/react';
 
export const underlinePlugin = UnderlinePlugin.configure({
  inputRules: [UnderlineRules.markdown()],
});
import { UnderlineRules } from '@platejs/basic-nodes';
import { UnderlinePlugin } from '@platejs/basic-nodes/react';
 
export const underlinePlugin = UnderlinePlugin.configure({
  inputRules: [UnderlineRules.markdown()],
});

Ownership

SurfaceOwnerWhat It Does
BaseUnderlinePlugin@platejs/basic-nodesHeadless underline mark, HTML parser, render tag, and toggle transform.
UnderlinePlugin@platejs/basic-nodes/reactReact wrapper with default mod+u shortcut.
UnderlineRules.markdown@platejs/basic-nodesOptional mark input rule factory.
BasicMarksKitRegistryAdds UnderlinePlugin with the underscore input rule.
MarkToolbarButtonRegistry UIReads active mark state and calls the mark toggle hook.

The package owns the mark. The registry owns toolbar placement and icon choice.

Behavior

BehaviorSource
Mark keyKEYS.underline
Leaf behaviornode.isLeaf: true
Toggle transformeditor.tf.underline.toggle() calls editor.tf.toggleMark(type).
ShortcutUnderlinePlugin registers mod+u.
HTML tagsu
HTML stylestext-decoration: underline
HTML guardIgnores descendants where textDecoration is none.
Render outputu

API Reference

APIPackageUse
BaseUnderlinePlugin@platejs/basic-nodesHeadless underline plugin.
UnderlinePlugin@platejs/basic-nodes/reactReact underline plugin with shortcut defaults.
UnderlineRules.markdown()@platejs/basic-nodesCreates the underline mark input rule.
tf.underline.toggle()@platejs/basic-nodesToggles the underline mark at the selection.