RichTextEditor
ImplementedRich text editor for event descriptions. Replaces TinyMCE. TipTap/Lexical wrapper.
patterns/molecules/richtexteditor.htmlWYSIWYG rich-text editor for form descriptions — a contentEditable surface driven by a TextFormatToolbar (bold/italic/headings/lists/link/quote/code/undo/redo via document.execCommand). Produces HTML; sanitize it before rendering anywhere.
RichTextEditor
molecules
Controlled or uncontrolled editor with an owned label/editor/hint stack. The surface is a role="textbox" contentEditable div; the sibling TextFormatToolbar is wired via aria-controls. Output is raw HTML — the onChange payload MUST be sanitized at render time (DOMPurify or equivalent).
Formatting is kept as HTML in the stored value.
This component supports light and dark mode.
Usage
RichTextEditor requires onChange — a bare <RichTextEditor /> render throws on the first keystroke. The controlled pattern pairs value with local state; the uncontrolled pattern seeds defaultValue and listens to onChange. The emitted HTML must be sanitized before rendering it anywhere (see Sanitization).
import { RichTextEditor } from '@epasslive/design-system'
const [description, setDescription] = useState('')
<RichTextEditor
id="description"
label="Event description"
helperText="Basic formatting is allowed."
value={description}
onChange={setDescription}
placeholder="Describe the event…"
minHeight={220}
commands={['undo', 'redo', 'bold', 'italic', 'h2', 'h3', 'ul', 'ol', 'link']}
/>Props
valuestringControlled editor content (HTML). Setting it re-renders the surface (guarded against cursor-jump loops).
defaultValuestring""Initial content when uncontrolled.
onChange*(html: string) => voidCalled with the surface innerHTML on every input and after every toolbar command. Required — omitting it crashes on first interaction.
placeholderstring"Start typing…"Placeholder text shown via data-placeholder + :empty pseudo-content. Defaults to English; pass a localized string in non-English locales.
disabledbooleanfalseDisables editing and the toolbar (aria-disabled, opacity 50).
readOnlybooleanfalseNon-editable preview mode (aria-readonly, no contentEditable).
commandsTextFormatCommand[]compact document setToolbar command subset — "bold" | "italic" | "underline" | "strikethrough" | "h1" | "h2" | "h3" | "ul" | "ol" | "link" | "quote" | "code" | "undo" | "redo". Defaults to a 12-command document set.
minHeightnumber200Minimum surface height in px (inline style; the surface grows with content).
linkPromptstring"Enter URL:"Prompt string shown by the link command. Localization escape hatch — the DS has no i18n mechanism yet.
ariaLabelstringAccessible name for the editor surface. Optional when label is set (aria-labelledby wiring takes over); an explicit ariaLabel wins over the visible label.
labelstringVisible field label above the toolbar. The component owns the label/editor/hint stack — do not hand-roll a sibling label.
requiredbooleanfalseMarks the field required; appends an aria-hidden * to the label and aria-required to the surface.
helperTextstringHelper text below the editor (rendered via the Caption atom), wired with aria-describedby.
hintstringAlias for helperText (dashboard-form naming).
errorstringError message; replaces the helper text and marks the surface aria-invalid (role="alert").
classNamestringAdditional CSS classes on the wrapper div.
idstringStable id for the editor surface (defaults to an auto-generated rte-* id; derives the label/helper/error ids).
Props
RichTextEditor
valuestring—Editor content (HTML)
onChange(html: string) => void—Content change handler
disabledbooleanfalseDisabled state
placeholderstring—Placeholder text
defaultValuestring''Initial value when uncontrolled.
readOnlybooleanfalseMakes the value read-only.
commandsTextFormatCommand[]—Synced from source — no interface JSDoc yet; document on `RichTextEditor.tsx`.
minHeightnumber200Synced from source — no interface JSDoc yet; document on `RichTextEditor.tsx`.
ariaLabelstring—Synced from source — no interface JSDoc yet; document on `RichTextEditor.tsx`.
labelstring—Visible label for the control.
requiredbooleanfalseMarks the field as required.
helperTextstring—Helper text rendered below the control.
hintstring—Alias for `helperText`.
errorstring—Error message; takes precedence over helper text.
linkPromptstring'Enter URL:'Prompt string for the link command (i18n escape hatch).
classNamestring—Additional CSS classes on the wrapper div.
idstring—Stable id; derives the label/helper/error ids.
<RichTextEditor />Accessibility
ARIA
2 rulesKeyboard
1 rulevalidation
1 ruleUsage
Import
import { RichTextEditor } from "@epasslive/design-system"Example 1
<RichTextEditor />Example 2
<RichTextEditor variant="default" />Anti-patterns
— Do not hardcode data in molecules
— Avoid complex business logic in molecules