Both @editorcn/editor and @editorcn/block-editor are styled using CSS custom properties (design tokens) defined by your shadcn/ui theme. This means they automatically adapt to your existing design system — light mode, dark mode, brand colors, border radius, and fonts.
How it works
The editors don't hardcode colors, spacing, or fonts. Instead, they reference CSS variables like var(--primary), var(--background), var(--border), and var(--radius).
These variables are defined in your shadcn globals:
/* globals.css */
:root {
--background: oklch(1 0 0);
--foreground: oklch(0.2686 0 0);
--primary: oklch(0.7686 0.1647 70.0804);
--border: oklch(0.9276 0.0058 264.5313);
--radius: 0.375rem;
--font-mono: JetBrains Mono, monospace;
/* ... */
}
.dark {
--background: oklch(0.2046 0 0);
--foreground: oklch(0.9219 0 0);
--border: oklch(0.3715 0 0);
/* ... */
}Tailwind v4 maps these to utility classes via @theme inline, and the editor CSS consumes them directly via var().
Dark mode
Both editors fully support dark mode. To enable it:
-
Set up
next-themeswithattribute="class":Copy import { ThemeProvider } from "next-themes"; function Providers({ children }) { return ( <ThemeProvider attribute="class" defaultTheme="system" enableSystem> {children} </ThemeProvider> ); } -
The
.darkclass on<html>automatically switches the editor's colors.
No editor-specific configuration is needed — it just works.
Customizing the theme globally
Override any CSS variable in your own stylesheet to change the editors' appearance:
Copy @import "@editorcn/editor/style.css"; @import "@editorcn/block-editor/style.css"; :root { --primary: oklch(0.6 0.2 250); --radius: 0.5rem; --font-mono: "Fira Code", monospace; } .dark { --background: oklch(0.15 0 0); --border: oklch(0.3 0 0); }
Available variables
| Variable | Affects |
|---|---|
--background | Editor background, toolbar background |
--foreground | Text color |
--primary | Links, active controls, checkboxes, syntax highlights |
--border | Editor border, toolbar separator, blockquote line, code block border, HR |
--muted | Code background, secondary backgrounds |
--muted-foreground | Placeholder text, blockquote text, muted labels |
--destructive | Danger items in dropdowns, syntax error highlights |
--accent-foreground | Syntax keyword/function highlights |
--radius | Editor border radius, code block radius, checkbox radius |
--font-mono | Code blocks, inline code |
--font-sans | Default editor text |
Scoping overrides to a single editor
Wrap an editor in a container with a CSS class and scope your overrides:
Copy .my-custom-editor { --primary: oklch(0.7 0.25 150); --radius: 0.25rem; }
Copy <div className="my-custom-editor"> <RichTextEditor editor={editor}> <RichTextEditor.Toolbar> <RichTextEditor.Bold /> </RichTextEditor.Toolbar> <RichTextEditor.Content /> </RichTextEditor> </div>
This keeps your global theme intact while giving a single editor a different look.
Per-instance className
Every component accepts a className prop that merges with the default classes using tailwind-merge.
RichTextEditor
Copy <RichTextEditor editor={editor} className="rounded-lg shadow-md"> <RichTextEditor.Toolbar className="bg-muted/50"> <RichTextEditor.Content className="min-h-[300px]" /> </RichTextEditor.Toolbar> </RichTextEditor>
BlockEditor
Copy <BlockEditor editor={editor} className="max-w-3xl mx-auto" />
CSS class reference
Override not applying? Editor styles are loaded from JS imports, which can affect CSS cascade order. If a simple class override doesn't work, add !important:
Copy .rte-editor-icon { width: 1.25rem !important; height: 1.25rem !important; }
Icons are inline SVGs — override .rte-editor-icon directly or via [data-variant="compact"] .rte-editor-icon for variant-specific sizing.
Every editor element has a scoped CSS class. Override any of these in your stylesheet to customize specific parts.
@editorcn/editor
| Class | What it styles |
|---|---|
.rte-root | Editor container (border, background, border-radius) |
.rte-toolbar | Toolbar bar (layout, sticky support) |
.rte-toolbar--subtle | Toolbar in subtle variant |
.rte-toolbar--compact | Toolbar in compact variant |
.rte-controls-group | Group of controls in the toolbar |
button.rte-control-button | Individual control buttons |
.rte-editor-icon | Icons inside control buttons |
.rte-content .ProseMirror | Content editing area |
.rte-content .ProseMirror p | Paragraphs |
.rte-content .ProseMirror h1–h6 | Headings |
.rte-content .ProseMirror ul | Unordered lists |
.rte-content .ProseMirror ol | Ordered lists |
.rte-content .ProseMirror li | List items |
.rte-content .ProseMirror blockquote | Blockquotes |
.rte-content .ProseMirror code | Inline code |
.rte-content .ProseMirror pre | Code blocks |
.rte-content .ProseMirror hr | Horizontal rules |
.rte-content .ProseMirror a | Links |
.rte-content .ProseMirror pre .hljs-* | Syntax highlighting tokens |
.rte-link-editor | Link editor popover |
.rte-link-editor-input | Link URL input field |
.rte-link-editor-save | Link save button |
.rte-task-list | Task list container |
.rte-task-list li | Task list items |
.rte-task-list input[type="checkbox"] | Task checkboxes |
@editorcn/block-editor
| Class | What it styles |
|---|---|
.block-editor | Editor container |
.block-editor-content .ProseMirror | Content editing area |
.block-editor-content .ProseMirror p | Paragraphs |
.block-editor-content .ProseMirror h1–h3 | Headings |
.block-editor-content .ProseMirror ul, ol | Lists |
.block-editor-content .ProseMirror li | List items |
.block-editor-content .ProseMirror blockquote | Blockquotes |
.block-editor-content .ProseMirror code | Inline code |
.block-editor-content .ProseMirror pre | Code blocks |
.block-editor-content .ProseMirror hr | Horizontal rules |
.block-editor-content .ProseMirror img | Images |
.block-editor-content .ProseMirror table, th, td | Tables |
.block-editor-content .ProseMirror .tableWrapper | Table horizontal scroll wrapper |
.block-editor-content .ProseMirror ul[data-type="taskList"] | Task lists |
.drag-handle | Block drag handle |
.block-editor-block-actions | Block actions menu container |
.block-editor-block-actions-trigger | Block actions trigger button (grip icon) |
.block-editor-block-actions-dropdown | Block actions dropdown |
.block-editor-block-actions-item | Block actions dropdown items |
.block-editor-bubble-menu | Floating bubble menu |
.block-editor-bubble-group | Bubble menu button group |
.block-editor-bubble-btn | Bubble menu buttons |
.block-editor-bubble-btn-text | Bubble menu button text label |
.block-editor-bubble-separator | Bubble menu separator lines |
.block-editor-bubble-dropdown | Bubble menu dropdown |
.block-editor-bubble-dropdown-item | Dropdown items (heading select, align, etc.) |
.block-editor-slash-menu | Slash command popup |
.block-editor-slash-menu-list | Slash command list container |
.block-editor-slash-menu-item | Slash command items |
.block-editor-slash-menu-item--selected | Selected slash command item |
.block-editor-slash-menu-item-content | Slash command item content wrapper |
.block-editor-slash-menu-item-label | Slash command item title |
.block-editor-slash-menu-item-desc | Slash command item description |
.block-editor-slash-menu-empty | Slash command empty state |
.block-editor-link-form | Link form inside bubble menu |
.block-editor-link-input | Link URL input |
.block-editor-link-actions | Link action buttons row |
.block-editor-btn | Base button style (used in actions, alerts) |
.block-editor-btn--primary, --ghost, --outline, --danger, --secondary | Button variants |
.block-editor-btn--sm, --md, --lg, --icon | Button sizes |
.block-editor-label | Form label |
.block-editor-textarea | Textarea (used in code block source editing) |
.block-editor-scroll-area | Scrollable container |
.block-editor-alert | Alert box |
Common customizations
Change icon size
Icons in the toolbar are rendered inside .rte-editor-icon. Override their size:
Copy .rte-editor-icon { width: 1.25rem; height: 1.25rem; }
Or for a specific variant:
Copy /* Compact variant icons are already smaller */ .rte-root[data-variant="compact"] .rte-editor-icon { width: 0.875rem; height: 0.875rem; }
Change control button size
Copy /* All variants */ button.rte-control-button { width: 2.25rem; height: 2.25rem; } /* Only default variant */ .rte-root[data-variant="default"] .rte-controls-group > button { min-width: 2rem; height: 2rem; }
Change paragraph font size
Copy .rte-content .ProseMirror p { font-size: 1.125rem; line-height: 1.8; }
For the block editor:
Copy .block-editor-content .ProseMirror p { font-size: 1.125rem; line-height: 1.8; }
Change heading sizes
Copy .rte-content .ProseMirror h1 { font-size: 2rem; } .rte-content .ProseMirror h2 { font-size: 1.5rem; } .rte-content .ProseMirror h3 { font-size: 1.25rem; }
Change content area min-height
Copy .rte-content .ProseMirror { min-height: 400px; }
Change toolbar button gap
Copy .rte-toolbar { gap: 0.5rem; }
Customize code blocks
Copy .rte-content .ProseMirror pre { background-color: #1e1e2e; color: #cdd6f4; border-radius: 0.5rem; padding: 1.25rem; font-size: 0.8125rem; }
Customize link editor popover
Copy .rte-link-editor { gap: 0.5rem; padding: 0.5rem; } .rte-link-editor-input { min-width: 250px; padding: 0.375rem 0.5rem; border: 1px solid var(--border); border-radius: calc(var(--radius) - 2px); }
Customize task checkboxes
Copy .rte-task-list input[type="checkbox"] { width: 20px; height: 20px; border-radius: 4px; }
Customize the bubble menu (block editor)
Copy .block-editor-bubble-menu { height: 2.5rem; padding: 0 0.5rem; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); } .block-editor-bubble-btn { height: 2rem; padding: 0 0.5rem; font-size: 0.875rem; } .block-editor-bubble-btn svg { width: 1rem; height: 1rem; }
Customize the slash command menu
Copy .block-editor-slash-menu { max-height: 400px; min-width: 240px; } .block-editor-slash-menu-item { padding: 0.625rem 0.75rem; } .block-editor-slash-menu-item-label { font-size: 0.875rem; } .block-editor-slash-menu-item-desc { font-size: 0.8125rem; }
Change block editor heading sizes
Copy .block-editor-content .ProseMirror h1 { font-size: 2rem; } .block-editor-content .ProseMirror h2 { font-size: 1.625rem; } .block-editor-content .ProseMirror h3 { font-size: 1.375rem; }
Customize drag handle
Copy .drag-handle { width: 1.5rem; height: 1.75rem; opacity: 1; color: var(--muted-foreground); } .drag-handle:hover { background: var(--accent); color: var(--accent-foreground); }
Variant-specific overrides
The editor uses data-variant attribute on the root element. Use it to target specific variants:
Copy /* Target subtle variant */ .rte-root[data-variant="subtle"] { box-shadow: 0 2px 6px rgba(0, 0, 0, 0.08); } /* Target compact variant */ .rte-root[data-variant="compact"] .rte-controls-group > button { min-width: 1.5rem; height: 1.5rem; }
Fonts
The editors use var(--font-sans) for body text and var(--font-mono) for code. Configure these in your globals.css:
Copy :root { --font-sans: Inter, sans-serif; --font-mono: JetBrains Mono, monospace; }
Or pass a custom className to the editor container:
Copy <RichTextEditor editor={editor} className="font-serif"> ... </RichTextEditor>
Import order
Import the editor CSS after your shadcn globals so variables are defined:
Copy @import "./globals.css"; /* your shadcn theme variables */ @import "@editorcn/editor/style.css"; @import "@editorcn/block-editor/style.css";
On This Page
How it worksDark modeCustomizing the theme globallyAvailable variablesScoping overrides to a single editorPer-instance classNameRichTextEditorBlockEditorCSS class reference@editorcn/editor@editorcn/block-editorCommon customizationsChange icon sizeChange control button sizeChange paragraph font sizeChange heading sizesChange content area min-heightChange toolbar button gapCustomize code blocksCustomize link editor popoverCustomize task checkboxesCustomize the bubble menu (block editor)Customize the slash command menuChange block editor heading sizesCustomize drag handleVariant-specific overridesFontsImport order