Rich Text Editor
@allem-ui/rich-text
Lightweight WYSIWYG editor with formatting toolbar, keyboard shortcuts, and dark mode. Zero dependencies — built on native contentEditable.
Installation
npm install @allem-ui/rich-textAdd the @source directive to your CSS so Tailwind generates the component classes:
@source "@allem-ui/rich-text";Editor
Full editor with toolbar. Try the formatting buttons and keyboard shortcuts.
Read-Only
Display formatted content without editing. Toolbar is automatically hidden.
Bubble Menu
Select text to reveal a floating toolbar with inline formatting options. The bubble menu appears automatically — hide the static toolbar for a distraction-free writing experience.
Hidden Toolbar
Use hideToolbar for a minimal writing experience. Keyboard shortcuts still work.
RichTextEditor Props
| Prop | Type | Default | Description |
|---|---|---|---|
| initialValue | string | "" | Initial HTML content |
| onChange | (html: string) => void | — | Called on content change with HTML string |
| placeholder | string | "Start writing..." | Placeholder text |
| readOnly | boolean | false | Read-only mode (hides toolbar) |
| minHeight | number | 120 | Minimum editor height in pixels |
| maxHeight | number | 400 | Maximum editor height in pixels |
| hideToolbar | boolean | false | Hide the formatting toolbar |
| hideBubbleMenu | boolean | false | Hide the floating bubble menu on text selection |
| className | string | — | Additional CSS classes |
useRichText
Hook for building a custom editor UI. Use this when you need full control over the toolbar and layout.
Options
| Prop | Type | Default | Description |
|---|---|---|---|
| initialValue | string | — | Initial HTML content |
| onChange | (html: string) => void | — | Called when content changes |
Return Value
| Prop | Type | Default | Description |
|---|---|---|---|
| editorRef | RefObject<HTMLDivElement> | — | Ref to attach to the editable element |
| html | string | — | Current HTML content |
| activeFormats | ActiveFormats | — | Object of currently active formatting states |
| selectionRect | SelectionRect | null | — | Bounding rect of the current text selection |
| hasSelection | boolean | — | Whether text is currently selected |
| handleInput | () => void | — | Input event handler |
| toggleBold | () => void | — | Toggle bold formatting |
| toggleItalic | () => void | — | Toggle italic formatting |
| toggleUnderline | () => void | — | Toggle underline formatting |
| toggleStrikethrough | () => void | — | Toggle strikethrough formatting |
| toggleHeading | (level: 1 | 2 | 3) => void | — | Toggle heading level |
| toggleOrderedList | () => void | — | Toggle ordered list |
| toggleUnorderedList | () => void | — | Toggle unordered list |
| toggleBlockquote | () => void | — | Toggle blockquote |
| toggleCodeBlock | () => void | — | Toggle code block |
| insertLink | (url: string) => void | — | Insert a link at selection |
| removeLink | () => void | — | Remove link from selection |
| insertHorizontalRule | () => void | — | Insert a horizontal rule |
| undo | () => void | — | Undo last action |
| redo | () => void | — | Redo last undone action |
BubbleMenu Props
Floating inline toolbar that appears on text selection. Built into RichTextEditor by default — use standalone with useRichText for custom layouts.
| Prop | Type | Default | Description |
|---|---|---|---|
| editorRef* | RefObject<HTMLDivElement> | — | Ref to the editable element |
| selectionRect* | SelectionRect | null | — | Bounding rect of the current selection |
| hasSelection* | boolean | — | Whether text is currently selected |
| activeFormats* | ActiveFormats | — | Currently active formatting states |
| onBold* | () => void | — | Toggle bold |
| onItalic* | () => void | — | Toggle italic |
| onUnderline* | () => void | — | Toggle underline |
| onStrikethrough* | () => void | — | Toggle strikethrough |
| onLink* | (url: string) => void | — | Insert a link |
| onRemoveLink* | () => void | — | Remove a link |
RichTextToolbar Props
Standalone toolbar component for custom editor layouts via useRichText.
| Prop | Type | Default | Description |
|---|---|---|---|
| activeFormats* | ActiveFormats | — | Current formatting state |
| onBold* | () => void | — | Toggle bold |
| onItalic* | () => void | — | Toggle italic |
| onUnderline* | () => void | — | Toggle underline |
| onStrikethrough* | () => void | — | Toggle strikethrough |
| onHeading* | (level: 1 | 2 | 3) => void | — | Toggle heading level |
| onOrderedList* | () => void | — | Toggle ordered list |
| onUnorderedList* | () => void | — | Toggle unordered list |
| onBlockquote* | () => void | — | Toggle blockquote |
| onCodeBlock* | () => void | — | Toggle code block |
| onLink* | (url: string) => void | — | Insert link |
| onRemoveLink* | () => void | — | Remove link |
| onUndo | () => void | — | Undo action |
| onRedo | () => void | — | Redo action |
| className | string | — | Additional CSS classes |
RichTextContent Props
The editable content area. Use with useRichText for custom layouts.
| Prop | Type | Default | Description |
|---|---|---|---|
| editorRef* | RefObject<HTMLDivElement> | — | Ref from useRichText |
| initialValue | string | "" | Initial HTML content |
| placeholder | string | "Start writing..." | Placeholder text |
| readOnly | boolean | false | Disable editing |
| minHeight | number | 120 | Minimum height in pixels |
| maxHeight | number | 400 | Maximum height in pixels |
| onInput* | () => void | — | Input handler from useRichText |
| onKeyDown | (e: KeyboardEvent) => void | — | Keyboard event handler |
| className | string | — | Additional CSS classes |
| children | ReactNode | — | Overlay elements like BubbleMenu |
ActiveFormats Type
| Prop | Type | Default | Description |
|---|---|---|---|
| bold | boolean | — | Bold is active |
| italic | boolean | — | Italic is active |
| underline | boolean | — | Underline is active |
| strikethrough | boolean | — | Strikethrough is active |
| orderedList | boolean | — | Ordered list is active |
| unorderedList | boolean | — | Unordered list is active |
| blockquote | boolean | — | Blockquote is active |
| code | boolean | — | Code block is active |
| heading1 | boolean | — | Heading 1 is active |
| heading2 | boolean | — | Heading 2 is active |
| heading3 | boolean | — | Heading 3 is active |
SelectionRect Type
| Prop | Type | Default | Description |
|---|---|---|---|
| top | number | — | Top position in pixels |
| left | number | — | Left position in pixels |
| width | number | — | Selection width in pixels |
| height | number | — | Selection height in pixels |
Keyboard Shortcuts
| Format | Shortcut |
|---|---|
| Bold | ⌘B |
| Italic | ⌘I |
| Underline | ⌘U |
| Undo | ⌘Z |
| Redo | ⌘⇧Z |
Markdown Shortcuts
Type these at the start of a new line to auto-convert into formatted blocks.
| Input | Result |
|---|---|
# | Heading 1 |
## | Heading 2 |
### | Heading 3 |
> | Blockquote |
- or * | Unordered list |
1. | Ordered list |
``` | Code block |
--- | Horizontal rule |
Toolbar Formats
The toolbar supports: Bold, Italic, Underline, Strikethrough, Heading 1–3, Ordered List, Unordered List, Blockquote, Code Block, Link, Undo, and Redo.