Zephora UI

Other

Editor

Minimal dependency-free rich text editor built on contentEditable, with a formatting toolbar (bold, italic, headings, lists, blockquote, code, links, alignment, text/highlight colors, images), a configurable command set, sanitized HTML pasting via stripUnsafeHtml and controlled or uncontrolled HTML value. Security note: value/defaultValue is rendered as-is by default — enable the opt-in sanitizeValue prop (or call stripUnsafeHtml yourself) whenever the HTML comes from an untrusted source.

Import

import { Editor, stripUnsafeHtml } from "@zephora/react";

Examples

Uncontrolled

Hello Zephora!

Controlled

`onValueChange` receives the current HTML after every edit.

Type here…

<p>Type here…</p>

Read only

`readOnly` disables editing and the toolbar.

Release notes

This content cannot be edited.

Full toolbar

The default toolbar includes links (select text first), alignment, text/highlight colors and image insertion. `commands` picks which buttons to show, in the given order.

Select me and try the link and color buttons.

Sanitizing pasted HTML

The editor already runs pasted HTML through stripUnsafeHtml (sanitizeOnPaste, on by default). The util is also exported on its own — here it cleans hostile markup: scripts, event handlers and javascript: URLs are removed, safe tags survive.

— press Sanitize —

API

Editor props

PropTypeDefaultDescription
valuestringControlled HTML value.
defaultValuestringInitial HTML for uncontrolled usage.
onValueChange(html: string) => voidCalled with the current HTML after every edit.
placeholderstringHint shown while the editor is empty.
readOnlybooleanfalseDisables editing and the toolbar.
minHeightnumber160Minimum block size of the editing area in px.
commandsEditorCommandName[]all commandsWhich toolbar commands to show, in the given order. EditorCommandName is one of: "bold" | "italic" | "underline" | "strikethrough" | "h1" | "h2" | "ul" | "ol" | "blockquote" | "code" | "link" | "unlink" | "alignLeft" | "alignCenter" | "alignRight" | "foreColor" | "hiliteColor" | "image" | "clear".
sanitizeOnPastebooleantrueRuns pasted HTML through stripUnsafeHtml before insertion (plain-text pastes are left untouched).
aria-labelstring"Rich text editor"Accessible name of the editing area.
unstyledbooleanfalseHeadless mode — skips Zephora styling.

stripUnsafeHtml(html) props

PropTypeDefaultDescription
html *stringHTML string to sanitize. Kept: p, br, b, strong, i, em, u, s, strike, h1–h3, ul, ol, li, blockquote, pre, code, a[href: http/https/mailto], img[src: http/https/data:image + alt], span[style: color/background-color/text-align], div[style: text-align]. script/style/iframe & co. are dropped with their content; unknown-but-harmless containers are unwrapped.
→ returnsstringSanitized HTML. Event-handler attributes and javascript: URIs are always removed. Pure function — safe to import without rendering the Editor; on the server (no DOM) it falls back to a best-effort regex pass, so run it on the client before trusting the output.

Keyboard

KeyAction
ArrowRight / ArrowLeftMoves focus between toolbar buttons (wraps around).
Enter / SpaceApplies the focused toolbar command.
TabMoves between the toolbar and the editing area.
Enter (in a link/image panel)Applies the URL / inserts the image.
Escape (in a panel or palette)Closes it and returns focus to its trigger button.