Rich text editor

WYSIWYG editor powered by TipTap, styled to match Squad UI.

Headings, lists, inline formatting, links, undo/redo.

Installation
$Terminal
npx shadcn@latest add https://sdk-components.thesqd.com/r/rich-text-editor.json
Usage
Use as a controlled (`value` + `onChange`) or uncontrolled (`defaultValue`) editor.
TSImport
import { RichTextEditor } from "@/components/ui/rich-text-editor";
TSExample
import * as React from "react";
import { RichTextEditor } from "@/components/ui/rich-text-editor";

export function Example() {
  const [value, setValue] = React.useState("<p>Hello <strong>Squad</strong>.</p>");
  return (
    <RichTextEditor
      value={value}
      onChange={setValue}
      placeholder="Start writing…"
    />
  );
}
Composition
Anatomy of the RichTextEditor.
RichTextEditor (TipTap-backed)
├── Toolbar (top or bottom)
│   ├── Headings (H1/H2/H3)
│   ├── Bold / Italic / Underline / Strike / Code
│   ├── Lists (bullet / ordered)
│   ├── Blockquote
│   ├── Link (popover)
│   ├── Undo / Redo
│   ├── Spell-check popover (optional, retext stack lazy-loaded)
│   └── Dictation mic (optional, Web Speech API)
├── EditorContent (contenteditable)
└── Footer (optional character count)
Default toolbar
Headings, lists, inline formatting, links, undo/redo.

Headings, lists, inline formatting, links, undo/redo.

Inline markdown (ClickUp-style description)
`RichTextEditorInline` — a flat, borderless variant that takes markdown in and out via `@tiptap/markdown`. There is no fixed toolbar; highlighting text raises a floating BubbleMenu with formatting tools, just like a ClickUp task description. Pass `collapsible` to clip long content to a fixed height with a fade and an Expand/Collapse toggle, like long code blocks. Type `/` at the start of a word for a slash-command palette (headings, lists, quote, code block, divider) — entries gated off via `disabledFeatures` are hidden from it too.

Flat ClickUp-style description — markdown in/out, highlight text for a floating toolbar.

Character limit
Cap content length using the character-count extension.

Enforced via @tiptap/extension-character-count.

Toolbar on bottom
Pin the toolbar below the editable area.
Error state
Pass a string to `error` to show the red outline and an inline message below the editor.
With caption
Pass `caption` to render helper copy under the label. Error wins when both are present.

Markdown-style formatting is supported.

With dictation
Pass `dictation` to mount a Web Speech API mic at the end of the toolbar. Chrome/Edge only — the button hides itself in unsupported browsers (Safari, Firefox, mobile WebKit).

Web Speech API mic in the toolbar — Chrome/Edge only; hides itself elsewhere.

With spell check
Pass `spellCheck` to lazily load the retext stack (spelling, repeated words, a/an, redundant acronyms, contractions, smart quotes, double spaces) and surface issues in a popover triggered from a toolbar button. The button shows a red badge with the issue count.

Lazy-loaded retext stack underlines misspellings, repeated words, a/an mistakes, and more. Hover an underline for the message.

Disabled
Read-only editor for display purposes.
API Reference
Props exposed by the RichTextEditor.

RichTextEditor

PropTypeDefaultDescription
valuestringControlled HTML value. Pair with `onChange`.
defaultValuestringUncontrolled initial HTML.
onChange(html: string) => voidFires whenever the editor content changes.
placeholderstringEmpty-state placeholder text.
disabledbooleanfalseRender as read-only.
toolbarPosition"top" | "bottom""top"Pin the toolbar above or below the editable region.
maxLengthnumberCap content via `@tiptap/extension-character-count`; shows a counter footer.
errorboolean | stringfalseError state. `true` applies the red outline only; a string also renders the inline message (`text-xs mt-1.5 text-red-500`) below the editor.
captionReactNodeHelper copy shown below the editor via FieldHint. Error wins when both are present.
dictationbooleanfalseMount a Web Speech API mic at the end of the toolbar. Streams transcribed phrases into the editor at the current cursor. Auto-hides in unsupported browsers (Safari, Firefox, mobile WebKit).
spellCheckbooleanfalseRun a lazy-loaded retext stack (retext-spell + dictionary-en, retext-repeated-words, retext-indefinite-article, retext-redundant-acronyms, retext-contractions, retext-quotes, retext-sentence-spacing) on the editor's text and surface issues in a toolbar popover with a count badge. Each entry shows the offending word + the retext message in a DescriptionList.
disabledFeaturesRichTextFeature[]Hide toolbar features, e.g. `["h1", "blockquote", "indent"]`. Features: bold, italic, underline, strike, code, h1, h2, h3, bulletList, orderedList, blockquote, link.
minHeightnumberMinimum editable area height in pixels.
classNamestringOverride or extend the wrapper classes.

RichTextEditorInline

PropTypeDefaultDescription
valuestringControlled markdown value. Pair with `onChange`.
defaultValuestringUncontrolled initial markdown.
onChange(markdown: string) => voidFires with the content serialized back to markdown via `editor.getMarkdown()`.
placeholderstring"Add a description…"Empty-state placeholder text.
disabledbooleanfalseRender as read-only.
minHeightnumber80Minimum editable area height in pixels.
collapsiblebooleanfalseCollapse the content to `collapsedHeight` with a fade-out gradient and an Expand overlay button, like collapsible code blocks. The toggle only appears when the content overflows.
defaultCollapsedbooleantrueInitial collapsed state for `collapsible`.
collapsedHeightnumber160Collapsed max-height in pixels.
collapsedLinesnumberCollapsed height expressed in text lines (24px each). Takes precedence over `collapsedHeight`.
autoHeightbooleanfalseFit the collapsed viewport to the space remaining below the editor in the browser viewport (re-measured on resize). Takes precedence over `collapsedLines`/`collapsedHeight`.
expandOnFocusbooleantrueAuto-expand when the editor gains focus (click/typing), like ClickUp descriptions.
disabledFeaturesRichTextFeature[]Hide toolbar features, e.g. `["h1", "blockquote", "indent"]`. Features: bold, italic, underline, strike, code, h1, h2, h3, bulletList, orderedList, blockquote, link, indent (indent is inline-only).
classNamestringOverride or extend the wrapper classes.