@openeditor/ui
v0.0.33
Published
Optional styled UI components for OpenEditor.
Readme
@openeditor/ui
Optional styled UI components for OpenEditor.
Public Surface
OpenEditorfor a composed editor surfaceOpenEditorSlashMenufor the default slash menu UIOpenEditorSelectionBubblefor inline formatting UIOpenEditorTableMenufor selection-aware row, column, header, cell, and table actionsOpenEditorButton,OpenEditorToggle,OpenEditorToggleGroup, andOpenEditorInputas Base UI-backed app primitivesOpenEditorContentanduseOpenEditorControllerre-exported from@openeditor/react
The UI package owns the default CSS and interactive primitives. User-facing controls are built on Base UI so focus management, keyboard behavior, dismiss behavior, and overlay positioning share one foundation.
Editor interaction contract
OpenEditor keeps keyboard ownership in the editable surface unless the user explicitly enters another control:
- Selecting text shows the formatting toolbar without moving focus. Delete,
Backspace, typing, arrow keys, and formatting/history shortcuts therefore keep
their normal editing meaning. The toolbar follows its document selection in
the editor's actual scroll container and hides once that selection is clipped.
Pointer presses on toolbar actions preserve the document selection.
Alt+F10moves focus into the toolbar, its arrow keys move between controls, andEscapereturns focus to the document. - Typing
/opens one flat, filtered command list. Focus stays in the document;ArrowUp/ArrowDown,Home/End, andPageUp/PageDownchange the active command,Enterruns it, andEscapedismisses the current slash session. Its anchor is resolved live from the document position while scrolling and is hidden when clipped. A dismissed session does not reopen merely because more query characters are typed. - The block handle menu is an explicit focus-owning menu.
EnterorSpaceopens it, menu arrow keys navigate it,Enterruns an action, andEscapeor an outside press closes it. Closing, dragging, and running an action all pass through the same unlock transition, so hover targeting cannot remain frozen. - Selecting a table cell shows a toolbar anchored to the table. Row and column menus preserve the cell selection while insert/delete commands run, and header, merge/split, and whole-table actions use the same transactional table controller as custom host UI.
Formatting and history shortcuts come from Tiptap's registered mark and history
extensions. OpenEditor keeps focus in the editor so those extension-owned
bindings receive Cmd on macOS and Ctrl elsewhere without a competing global
shortcut layer.
Theming
Use the typed theme contract instead of targeting OpenEditor implementation classes or defining global custom properties. The provider scopes tokens to editor content and automatically forwards them to portaled menus and dialogs. surfaceRaised is required and controls the background of menus, popovers, and dialogs.
import {
OpenEditor,
OpenEditorThemeProvider,
type OpenEditorTheme,
} from "@openeditor/ui";
const theme = {
surface: "var(--background)",
surfaceRaised: "var(--popover)",
surfaceMuted: "var(--muted)",
blockSurface: "var(--card)",
text: "var(--foreground)",
structuralLine: "var(--border)",
accentStrong: "var(--primary)",
bodyFontSize: "1rem",
bodyLineHeight: "1.65",
headingFont: "var(--font-display)",
headingWeight: "650",
heading1Size: "2.25rem",
heading2Size: "1.75rem",
radiusLarge: "1rem",
} satisfies OpenEditorTheme;
export function Editor() {
return <OpenEditor theme={theme} />;
}
export function HeadlessComposition() {
return (
<OpenEditorThemeProvider theme={theme}>
{/* OpenEditorContent, OpenEditorSelectionBubble, OpenEditorTableMenu, OpenEditorSlashMenu */}
</OpenEditorThemeProvider>
);
}createOpenEditorThemeStyle is available for non-React integrations that need the same canonical token-to-CSS mapping.
Semantic typography tokens cover body size and line height, heading font and
line height, heading weight, and independent sizes for heading levels one through
six. These tokens apply equally to editable content, the React viewer, and safe
HTML mounted under .oe-viewer; print- or product-specific page geometry remains
the host's responsibility.
Quick Start
import "@openeditor/ui/styles.css";
import { OpenEditor } from "@openeditor/ui";
export function Example() {
return <OpenEditor />;
}