Skip to content

Theming

You can customize colors, typography, and spacing using CSS variables.

Importing Styles

Default Styles

Import the default stylesheet:

typescript
import '@editu/core/styles.css';

This includes CSS variable definitions (light and dark themes), component styles, and typography styles.

Components Only (shadcn/ui)

For projects using shadcn/ui or custom CSS variables:

typescript
import '@editu/core/components.css';

This includes only component styles without CSS variable definitions.


Theme Provider

Use the EdituThemeProvider to enable dark mode support:

tsx
import { EdituThemeProvider } from '@editu/react';

function App() {
  return (
    <EdituThemeProvider 
      defaultTheme="system" 
      storageKey="my-app-theme"
    >
      <Editor />
    </EdituThemeProvider>
  );
}

EdituThemeProvider Options

PropertyTypeDefaultDescription
defaultTheme"light" | "dark" | "system""system"Default theme
storageKeystring"editu-theme"localStorage key for persistence
targetSelectorstringdocument.documentElementElement to apply theme attribute
disableTransitionOnChangebooleanfalseDisable transitions during theme change

Using Theme State

tsx
import { useEdituTheme } from '@editu/react';

function ThemeToggle() {
  const { theme, resolvedTheme, setTheme } = useEdituTheme();
  
  return (
    <select value={theme} onChange={(e) => setTheme(e.target.value)}>
      <option value="light">Light</option>
      <option value="dark">Dark</option>
      <option value="system">System</option>
    </select>
  );
}

Theme State Properties

PropertyTypeDescription
theme"light" | "dark" | "system"Current theme setting
resolvedTheme"light" | "dark"Actual resolved theme
systemTheme"light" | "dark"System preference
setTheme(theme) => voidFunction to change theme

CSS Variables

Editu uses CSS custom properties (variables) for all visual styling. You can override these to customize the appearance.

Theme Selectors

css
/* Light theme (default) */
:root,
.light,
[data-theme="light"],
[data-editu-theme="light"] {
  /* Light theme variables */
}

/* Dark theme */
.dark,
[data-theme="dark"],
[data-editu-theme="dark"] {
  /* Dark theme variables */
}

Color Variables

Primary Colors

VariableDescription
--editu-primaryPrimary brand color
--editu-primary-hoverPrimary hover state
--editu-primary-activePrimary active state
--editu-primary-foregroundText on primary background
--editu-primary-bgPrimary background (10% opacity)
--editu-primary-bg-hoverPrimary background hover

Secondary Colors

VariableDescription
--editu-secondarySecondary color
--editu-secondary-hoverSecondary hover state
--editu-secondary-foregroundText on secondary background

Background & Foreground

VariableDescription
--editu-backgroundMain background
--editu-background-secondarySecondary background
--editu-background-tertiaryTertiary background
--editu-foregroundMain text color
--editu-foreground-secondarySecondary text color
--editu-foreground-mutedMuted text color

UI Colors

VariableDescription
--editu-mutedMuted background
--editu-muted-foregroundMuted foreground
--editu-accentAccent background
--editu-accent-foregroundAccent foreground
--editu-borderBorder color
--editu-border-hoverBorder hover color

State Colors

VariableDescription
--editu-hover-bgHover background
--editu-active-bgActive background
--editu-successSuccess color
--editu-warningWarning color
--editu-errorError color
--editu-destructiveDestructive action color

Example: Custom Colors

Editu uses the OKLCH color space for all color values. Here's an example of custom color overrides:

css
:root {
  /* Brand colors (using OKLCH) */
  --editu-primary: oklch(0.623 0.214 259.815);
  --editu-primary-hover: oklch(0.546 0.245 262.881);
  --editu-primary-active: oklch(0.488 0.243 264.376);
  --editu-primary-foreground: oklch(1 0 0);
  
  /* Background */
  --editu-background: oklch(1 0 0);
  --editu-background-secondary: oklch(0.985 0 0);
  --editu-foreground: oklch(0.21 0.006 285.885);
  
  /* Borders */
  --editu-border: oklch(0.922 0 0);
}

[data-editu-theme="dark"] {
  --editu-primary: oklch(0.707 0.165 254.624);
  --editu-primary-hover: oklch(0.623 0.214 259.815);
  
  --editu-background: oklch(0.21 0.006 285.885);
  --editu-background-secondary: oklch(0.145 0 0);
  --editu-foreground: oklch(0.985 0 0);
  
  --editu-border: oklch(0.279 0.041 260.031);
}

Typography Variables

Font Families

VariableDefault
--editu-font-sanssystem-ui, -apple-system, sans-serif
--editu-font-serifGeorgia, serif
--editu-font-monoui-monospace, monospace

Font Sizes

VariableValue
--editu-font-size-xs0.75rem
--editu-font-size-sm0.875rem
--editu-font-size-base1rem
--editu-font-size-lg1.125rem
--editu-font-size-xl1.25rem
--editu-font-size-2xl1.5rem
--editu-font-size-3xl1.875rem
--editu-font-size-4xl2.25rem

Line Heights

VariableValue
--editu-line-height-tight1.25
--editu-line-height-snug1.375
--editu-line-height-normal1.5
--editu-line-height-relaxed1.625
--editu-line-height-loose2

Font Weights

VariableValue
--editu-font-weight-normal400
--editu-font-weight-medium500
--editu-font-weight-semibold600
--editu-font-weight-bold700

Spacing Variables

VariableValue
--editu-spacing-00
--editu-spacing-10.25rem
--editu-spacing-20.5rem
--editu-spacing-30.75rem
--editu-spacing-41rem
--editu-spacing-51.25rem
--editu-spacing-61.5rem
--editu-spacing-82rem
--editu-spacing-102.5rem
--editu-spacing-123rem

Border Radius Variables

VariableValue
--editu-radius-none0
--editu-radius-sm0.25rem
--editu-radius-md0.375rem
--editu-radius-lg0.5rem
--editu-radius-xl0.75rem
--editu-radius-2xl1rem
--editu-radius-full9999px

Shadow Variables

VariableDescription
--editu-shadow-smSmall shadow
--editu-shadow-mdMedium shadow
--editu-shadow-lgLarge shadow
--editu-shadow-xlExtra large shadow
--editu-shadow-2xl2XL shadow

Transition Variables

VariableValue
--editu-transition-fast100ms
--editu-transition-normal150ms
--editu-transition-slow300ms

Z-Index Variables

VariableValueDescription
--editu-z-dropdown50Dropdowns
--editu-z-sticky60Sticky elements
--editu-z-fixed70Fixed elements
--editu-z-modal-backdrop80Modal backdrop
--editu-z-modal90Modals
--editu-z-popover100Popovers
--editu-z-tooltip110Tooltips

Component-Specific Variables

Editor

VariableDefaultDescription
--editu-editor-min-height350pxMinimum editor height
--editu-editor-paddingvar(--editu-spacing-6)Editor padding
--editu-editor-font-familyvar(--editu-font-sans)Editor font
--editu-editor-font-sizevar(--editu-font-size-base)Editor font size
--editu-editor-line-heightvar(--editu-line-height-relaxed)Editor line height

Images

VariableDefaultDescription
--editu-image-border-radiusvar(--editu-radius-lg)Image border radius
--editu-image-outline-colorvar(--editu-primary)Selected image outline
--editu-image-outline-width2pxOutline width
--editu-resize-handle-colorvar(--editu-primary)Resize handle color
--editu-resize-handle-width8pxResize handle width
--editu-resize-handle-height48pxResize handle height

Code Blocks

VariableDescription
--editu-code-block-bgBackground color
--editu-code-block-textText color
--editu-code-block-toolbar-bgToolbar background
--editu-code-block-gutter-bgLine number gutter background
--editu-code-block-line-number-colorLine number color
--editu-code-block-language-colorLanguage indicator color
--editu-code-block-placeholderPlaceholder text color
--editu-code-block-button-colorButton text color
--editu-code-block-button-borderButton border color
--editu-code-block-button-hover-bgButton hover background
--editu-code-block-input-bgInput background
--editu-code-block-input-borderInput border

Mathematics

VariableDefaultDescription
--editu-math-block-bgvar(--editu-background-secondary)Block math background
--editu-math-inline-bgtransparentInline math background

Portal

VariableDefaultDescription
--editu-portal-base-z-index9999Base z-index for portals

shadcn/ui Integration

You can map shadcn/ui CSS variables to Editu. Note that shadcn/ui uses HSL format while Editu uses OKLCH, but CSS custom properties can reference each other:

css
:root {
  /* Map shadcn colors to Editu */
  --editu-primary: hsl(var(--primary));
  --editu-primary-foreground: hsl(var(--primary-foreground));
  --editu-background: hsl(var(--background));
  --editu-foreground: hsl(var(--foreground));
  --editu-border: hsl(var(--border));
  --editu-muted: hsl(var(--muted));
  --editu-muted-foreground: hsl(var(--muted-foreground));
  --editu-accent: hsl(var(--accent));
  --editu-accent-foreground: hsl(var(--accent-foreground));
  --editu-destructive: hsl(var(--destructive));
  
  /* Map radius */
  --editu-radius-sm: calc(var(--radius) - 4px);
  --editu-radius-md: calc(var(--radius) - 2px);
  --editu-radius-lg: var(--radius);
}

For detailed integration instructions, see the CSS Variables Reference.


Preventing Flash of Unstyled Content

Add the theme init script to your HTML <head> to prevent a flash of unstyled content:

typescript
import { getEdituThemeInitScript } from '@editu/core';

// In your HTML head
const script = getEdituThemeInitScript('my-theme-key');
// <script>{script}</script>

Or manually:

html
<script>
  (function() {
    const stored = localStorage.getItem('my-theme-key');
    const theme = stored || 'system';
    const resolved = theme === 'system'
      ? (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')
      : theme;
    document.documentElement.setAttribute('data-editu-theme', resolved);
  })();
</script>

Next Steps

Released under the MIT License.