Styling
Customize the appearance of rtecn editors.
Styling
Both @rtecn/editor and @rtecn/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":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:
@import "@rtecn/editor/style.css";
@import "@rtecn/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:
.my-custom-editor {
--primary: oklch(0.7 0.25 150);
--radius: 0.25rem;
}<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
<RichTextEditor editor={editor} className="rounded-lg shadow-md">
<RichTextEditor.Toolbar className="bg-muted/50">
<RichTextEditor.Content className="min-h-[300px]" />
</RichTextEditor.Toolbar>
</RichTextEditor>BlockEditor
<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:
.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.
@rtecn/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 |
@rtecn/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:
.rte-editor-icon {
width: 1.25rem;
height: 1.25rem;
}Or for a specific variant:
/* Compact variant icons are already smaller */
.rte-root[data-variant="compact"] .rte-editor-icon {
width: 0.875rem;
height: 0.875rem;
}Change control button size
/* 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
.rte-content .ProseMirror p {
font-size: 1.125rem;
line-height: 1.8;
}For the block editor:
.block-editor-content .ProseMirror p {
font-size: 1.125rem;
line-height: 1.8;
}Change heading sizes
.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
.rte-content .ProseMirror {
min-height: 400px;
}Change toolbar button gap
.rte-toolbar {
gap: 0.5rem;
}Customize code blocks
.rte-content .ProseMirror pre {
background-color: #1e1e2e;
color: #cdd6f4;
border-radius: 0.5rem;
padding: 1.25rem;
font-size: 0.8125rem;
}Customize link editor popover
.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
.rte-task-list input[type="checkbox"] {
width: 20px;
height: 20px;
border-radius: 4px;
}Customize the bubble menu (block editor)
.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
.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
.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
.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:
/* 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:
:root {
--font-sans: Inter, sans-serif;
--font-mono: JetBrains Mono, monospace;
}Or pass a custom className to the editor container:
<RichTextEditor editor={editor} className="font-serif">
...
</RichTextEditor>Import order
Import the editor CSS after your shadcn globals so variables are defined:
@import "./globals.css"; /* your shadcn theme variables */
@import "@rtecn/editor/style.css";
@import "@rtecn/block-editor/style.css";