Theming

Updated 8 April 2026

Master light/dark toggles, CSS variable overrides, brand palettes, and responsive typography so your editor looks like a first-class citizen inside any design system.

Here you’ll learn how the built-in light/dark experiences work, how system preference detection and the toolbar toggle share state, and how to override every visual detail with CSS variables, custom classes, and responsive tweaks. Use the snippets below to craft branded toolbars, apply gradients, tune typography, or ship complete theme bundles that feel native to your product.

Overview

The editor ships with a layered theming system: global CSS variables define the design tokens, built-in light/dark variants consume those tokens, and any custom class or CSS-in-JS solution can override specific slices without fighting inline styles.

  • Detection pipeline: prefers explicit prop/theme toggle state, then falls back to prefers-color-scheme, and finally defaults to light.
  • State sharing: the toolbar toggle, theme provider, and persisted localStorage key all point to the same internal store so UI never drifts out of sync.
  • Override strategy: change CSS variables for broad strokes, attach custom classes for component-level tweaks, or reach for render props to alter toolbars entirely.

Built-in Themes

Light Theme

The default light theme provides a clean, modern appearance.

Use the light preset when you want neutral grays, subtle separators, and predictable contrast ratios out of the box. Every toolbar and dropdown inherits from the :root token set, so swapping fonts or accent colors only requires overriding a handful of CSS variables.

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';

function LightThemeEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');

  return (
    <Editor
      value={content}           // Current HTML content
      onChange={setContent}     // Update state when content changes
      height={400}              // Editor height in pixels
      width="100%"              // Full width of container
    />
  );
}

Dark Theme

The dark theme automatically activates based on system preferences or user selection.

The dark preset intentionally reduces saturation, boosts foreground contrast, and recalibrates focus rings so the editor feels comfortable during late-night editing sessions. If you ship your own dark palette, override the [data-theme="dark"] token block to ensure the toggle keeps functioning.

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';

function ThemeToggleEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');

  return (
    <Editor
      value={content}           // Current HTML content
      onChange={setContent}     // Update state when content changes
      height={400}              // Editor height in pixels
      width="100%"              // Full width of container
    />
  );
}

Theme Toggle

Users can toggle between themes using the theme button (🌙/☀️) in the toolbar. Behind the scenes the editor writes the active value to localStorage[@webbycrown/rte:theme] and rehydrates it on mount so refreshes or route transitions do not reset the preference.

  1. Detect: On first render the editor inspects the explicit theme prop, then the stored preference, and finally window.matchMedia('(prefers-color-scheme: dark)').
  2. Persist: Clicking the toggle updates the internal store, rerenders the toolbar, and writes the value to storage so multiple editor instances stay aligned.
  3. Customize: If you need a different storage key, wrap the editor in your own provider and mirror the setter/getter while passing the resolved theme via props.

Custom Styling

For product-level polish you rarely want to fork the core styles; instead, scope overrides through CSS classes or CSS-in-JS wrappers so upgrades remain painless. The editor exposes stable class names on every major surface (container, toolbar rows, dropdowns, content canvas) specifically for this purpose.

CSS Classes

Override default styles using CSS classes. The snippet below highlights common hooks, but you can also target states like .rte-toolbar-button.is-active or .rte-editor-content blockquote to align the editor with the rest of your design system.

// Main container
.rte-editor-container {
  border: 1px solid #ccc;
  border-radius: 8px;
  background: #fff;
}

// Toolbar
.rte-toolbar {
  background: #f5f5f5;
  border-bottom: 1px solid #ddd;
  padding: 10px;
}

// Toolbar buttons
.rte-toolbar-button {
  padding: 8px 12px;
  border-radius: 4px;
  transition: background 0.2s;
}

.rte-toolbar-button:hover {
  background: #e0e0e0;
}

// Editor content
.rte-editor-content {
  min-height: 300px;
  padding: 20px;
  font-family: 'Arial', sans-serif;
}

Custom Class Names

Use the className prop to add custom classes to the editor container. This allows you to apply your own CSS styles, integrate with CSS frameworks like Tailwind CSS or Bootstrap, or target the editor with custom selectors for styling purposes. The className prop accepts a string of space-separated class names, which will be applied to the root editor element.

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Custom CSS file for styling
import './custom-editor.css';

function CustomStyledEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');

  return (
    <Editor
      className="my-custom-editor"  // Custom CSS class for styling
      value={content}               // Current HTML content
      onChange={setContent}         // Update state when content changes
      height={400}                  // Editor height in pixels
    />
  );
}

CSS file (custom-editor.css):

.my-custom-editor .rte-toolbar {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
}
.my-custom-editor .rte-toolbar-button {
  color: white;
}
.my-custom-editor .rte-toolbar-button:hover {
  background: rgba(255, 255, 255, 0.2);
}

Theme Variables

You can override CSS variables for consistent theming. These tokens cover high-level surfaces (background, borders), semantic colors (primary, secondary), and interaction states (hover, focus) so you can restyle the editor without diving into every selector.

  • Surface tokens: --rte-background--rte-border-color, and --rte-hover-background drive the canvas, toolbar, and dropdown shells.
  • Typography tokens: --rte-text-color and --rte-placeholder-color keep content accessible across light/dark modes.
  • Accent tokens: --rte-primary-color and --rte-secondary-color define active button states, caret colors, and selection outlines.
:root {
  --rte-primary-color: #667eea;
  --rte-secondary-color: #764ba2;
  --rte-background: #ffffff;
  --rte-text-color: #333333;
  --rte-border-color: #e0e0e0;
  --rte-hover-background: #f5f5f5;
}
[data-theme="dark"] {
  --rte-background: #1a1a1a;
  --rte-text-color: #ffffff;
  --rte-border-color: #333333;
  --rte-hover-background: #2a2a2a;
}

Custom Color Schemes

When you need more opinionated visuals—marketing pages, branded dashboards, customer specific palettes—wrap the editor in a namespaced class and override only the tokens and selectors you care about. Use different classes per brand, or dynamically swap the className based on tenant data.

Example: Blue Theme

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Custom CSS file for styling
import './blue-theme.css';

function BlueThemedEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');

  return (
    <Editor
      className="blue-theme"        // Custom CSS class for blue theme
      value={content}               // Current HTML content
      onChange={setContent}         // Update state when content changes
      height={400}                  // Editor height in pixels
    />
  );
}

CSS file (blue-theme.css):

.blue-theme .rte-toolbar {
  background: #2196F3;
  color: white;
}

.blue-theme .rte-toolbar-button {
  color: white;
}

.blue-theme .rte-toolbar-button:hover {
  background: rgba(255, 255, 255, 0.2);
}

.blue-theme .rte-editor-content {
  background: #E3F2FD;
}

Example: Green Theme

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Custom CSS file for styling
import './green-theme.css';

function GreenThemedEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');

  return (
    <Editor
      className="green-theme"       // Custom CSS class for green theme
      value={content}               // Current HTML content
      onChange={setContent}         // Update state when content changes
      height={400}                  // Editor height in pixels
    />
  );
}

Complete Theme Example

import React, { useState } from 'react';
import Editor from '@webbycrown/react-advanced-richtext-editor';
// Import the default stylesheet - required for proper editor appearance
import '@webbycrown/react-advanced-richtext-editor/dist/styles.css';
// Custom CSS file for styling
import './custom-theme.css';
function ThemedEditor() {
  // Store HTML content in state
  const [content, setContent] = useState('');
  return (
    <Editor
      className="custom-theme"      // Custom CSS class for custom theme
      value={content}               // Current HTML content
      onChange={setContent}         // Update state when content changes
      height={500}                  // Editor height in pixels
    />
  );
}

Tips

  • Test in Both Themes: Always test your custom styles in both light and dark themes. Simulate system-level toggles and verify there are no unreadable chips, icons, or focus outlines.
  • Use CSS Variables: Use CSS variables for easy theme switching. When you scope overrides through tokens, dark/light variants automatically inherit the correct hue without duplicating selectors.
  • Maintain Contrast: Ensure sufficient contrast for accessibility. Run WCAG contrast checks on toolbar buttons, dropdown options, and placeholder text.
  • Responsive Design: Test your theme on different screen sizes. Toolbars collapse into multiple rows on narrow viewports—confirm padding, borders, and gradients still look intentional.
  • Browser Compatibility: Test custom styles across different browsers. Pay special attention to Safari’s handling of backdrop-filter, scrollbars, and contentEditable selection colors.