Rtecn

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:

  1. Set up next-themes with attribute="class":

    import { ThemeProvider } from "next-themes";
    
    function Providers({ children }) {
      return (
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
          {children}
        </ThemeProvider>
      );
    }
  2. The .dark class 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

VariableAffects
--backgroundEditor background, toolbar background
--foregroundText color
--primaryLinks, active controls, checkboxes, syntax highlights
--borderEditor border, toolbar separator, blockquote line, code block border, HR
--mutedCode background, secondary backgrounds
--muted-foregroundPlaceholder text, blockquote text, muted labels
--destructiveDanger items in dropdowns, syntax error highlights
--accent-foregroundSyntax keyword/function highlights
--radiusEditor border radius, code block radius, checkbox radius
--font-monoCode blocks, inline code
--font-sansDefault 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

ClassWhat it styles
.rte-rootEditor container (border, background, border-radius)
.rte-toolbarToolbar bar (layout, sticky support)
.rte-toolbar--subtleToolbar in subtle variant
.rte-toolbar--compactToolbar in compact variant
.rte-controls-groupGroup of controls in the toolbar
button.rte-control-buttonIndividual control buttons
.rte-editor-iconIcons inside control buttons
.rte-content .ProseMirrorContent editing area
.rte-content .ProseMirror pParagraphs
.rte-content .ProseMirror h1h6Headings
.rte-content .ProseMirror ulUnordered lists
.rte-content .ProseMirror olOrdered lists
.rte-content .ProseMirror liList items
.rte-content .ProseMirror blockquoteBlockquotes
.rte-content .ProseMirror codeInline code
.rte-content .ProseMirror preCode blocks
.rte-content .ProseMirror hrHorizontal rules
.rte-content .ProseMirror aLinks
.rte-content .ProseMirror pre .hljs-*Syntax highlighting tokens
.rte-link-editorLink editor popover
.rte-link-editor-inputLink URL input field
.rte-link-editor-saveLink save button
.rte-task-listTask list container
.rte-task-list liTask list items
.rte-task-list input[type="checkbox"]Task checkboxes

@rtecn/block-editor

ClassWhat it styles
.block-editorEditor container
.block-editor-content .ProseMirrorContent editing area
.block-editor-content .ProseMirror pParagraphs
.block-editor-content .ProseMirror h1h3Headings
.block-editor-content .ProseMirror ul, olLists
.block-editor-content .ProseMirror liList items
.block-editor-content .ProseMirror blockquoteBlockquotes
.block-editor-content .ProseMirror codeInline code
.block-editor-content .ProseMirror preCode blocks
.block-editor-content .ProseMirror hrHorizontal rules
.block-editor-content .ProseMirror imgImages
.block-editor-content .ProseMirror table, th, tdTables
.block-editor-content .ProseMirror .tableWrapperTable horizontal scroll wrapper
.block-editor-content .ProseMirror ul[data-type="taskList"]Task lists
.drag-handleBlock drag handle
.block-editor-block-actionsBlock actions menu container
.block-editor-block-actions-triggerBlock actions trigger button (grip icon)
.block-editor-block-actions-dropdownBlock actions dropdown
.block-editor-block-actions-itemBlock actions dropdown items
.block-editor-bubble-menuFloating bubble menu
.block-editor-bubble-groupBubble menu button group
.block-editor-bubble-btnBubble menu buttons
.block-editor-bubble-btn-textBubble menu button text label
.block-editor-bubble-separatorBubble menu separator lines
.block-editor-bubble-dropdownBubble menu dropdown
.block-editor-bubble-dropdown-itemDropdown items (heading select, align, etc.)
.block-editor-slash-menuSlash command popup
.block-editor-slash-menu-listSlash command list container
.block-editor-slash-menu-itemSlash command items
.block-editor-slash-menu-item--selectedSelected slash command item
.block-editor-slash-menu-item-contentSlash command item content wrapper
.block-editor-slash-menu-item-labelSlash command item title
.block-editor-slash-menu-item-descSlash command item description
.block-editor-slash-menu-emptySlash command empty state
.block-editor-link-formLink form inside bubble menu
.block-editor-link-inputLink URL input
.block-editor-link-actionsLink action buttons row
.block-editor-btnBase button style (used in actions, alerts)
.block-editor-btn--primary, --ghost, --outline, --danger, --secondaryButton variants
.block-editor-btn--sm, --md, --lg, --iconButton sizes
.block-editor-labelForm label
.block-editor-textareaTextarea (used in code block source editing)
.block-editor-scroll-areaScrollable container
.block-editor-alertAlert 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;
}
.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";

On this page