Skip to main content

Bring Your Own Theme

You can customize the appearance of the editor and the documents you write by providing your own CSS stylesheet that will be loaded at runtime. This allows you to use your own styling preferences, override default styles, and create custom classes while using the built-in design system.

How Theming Works

The application uses CSS custom properties (variables) as design tokens. These tokens define colors, spacing, and other visual properties throughout the interface. When you create custom CSS, you can reference these same tokens to ensure your styles automatically adapt to theme changes (light/dark mode, custom themes, etc.).

OKLCH Color Space

All color tokens use the OKLCH color space (Oklab Lightness Chroma Hue), a modern perceptually uniform color space that offers significant advantages over traditional RGB/Hex colors:

Why OKLCH?

  • Perceptual uniformity: Changes in OKLCH values correspond to how humans actually perceive color differences
  • Predictable lightness: The lightness channel directly correlates to perceived brightness, making it easy to create accessible color variations
  • Consistent chroma: Colors with the same chroma value appear equally vibrant regardless of hue
  • Better gradients: Interpolating between OKLCH colors produces more natural-looking gradients than RGB
  • Automatic transformations: Programmatic color manipulation (lightening, darkening, adjusting saturation) produces more predictable and visually pleasing results

Benefits for theming:

  • Easier to create harmonious color palettes that work in both light and dark modes
  • Better accessibility through predictable contrast ratios
  • More reliable automatic color generation for hover states, variants, and related colors
  • Smoother animations and transitions between theme changes

Integration with Tailwind

All Tailwind utility classes (like text-primary, bg-surface, border-border) are built on top of these CSS variables. This means:

  • Tailwind classes automatically respect theme changes
  • Your custom CSS can use the same variables for consistency
  • Light and dark modes work seamlessly across all styles
  • All colors automatically benefit from OKLCH's perceptual uniformity

Writing Custom Classes

You can create semantic CSS classes that use design tokens and apply them to directives in your documents.

Basic Example

Your custom CSS:

.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
padding: 1.5rem;
}

.card__title {
color: var(--color-primary);
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 0.5rem;
}

.card__content {
color: var(--color-on-surface);
line-height: 1.6;
}

In your markdown document:

{{div class="card"}}
{{div class="card__title"}}Important Notice{{/div}}
{{div class="card__content"}}
This is a custom styled card using semantic class names.
{{/div}}
{{/div}}

BEM (Block Element Modifier) Style

The BEM methodology helps create reusable, maintainable components:

/* Block */
.alert {
padding: 1rem;
border-radius: var(--border-radius);
border-left: 4px solid currentColor;
}

/* Elements */
.alert__icon {
display: inline-block;
margin-right: 0.5rem;
}

.alert__message {
color: var(--color-on-surface);
}

/* Modifiers */
.alert--info {
background-color: var(--color-info);
color: var(--color-on-info);
}

.alert--success {
background-color: var(--color-success);
color: var(--color-on-success);
}

.alert--warning {
background-color: var(--color-warning);
color: var(--color-on-warning);
}

.alert--error {
background-color: var(--color-error);
color: var(--color-on-error);
}

Usage:

{{div class="alert alert--success"}}
{{span class="alert__icon"}}✓{{/span}}
{{span class="alert__message"}}Operation completed successfully!{{/span}}
{{/div}}

OOCSS (Object-Oriented CSS) Style

OOCSS separates structure from skin for maximum reusability:

/* Structure */
.media {
display: flex;
gap: 1rem;
}

.media__figure {
flex-shrink: 0;
}

.media__body {
flex-grow: 1;
}

/* Skin */
.box {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
padding: 1rem;
}

.box--elevated {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.text-muted {
color: var(--color-on-surface-variant);
}

Usage:

{{div class="media box box--elevated"}}
{{div class="media__figure"}}
🎨
{{/div}}
{{div class="media__body"}}
{{div}}Design System{{/div}}
{{div class="text-muted"}}Consistent, scalable styling{{/div}}
{{/div}}
{{/div}}

Combining Custom CSS with Tailwind

You can mix your custom classes with Tailwind utilities for maximum flexibility:

.feature-card {
background: linear-gradient(
135deg,
var(--color-primary),
var(--color-secondary)
);
position: relative;
overflow: hidden;
}

.feature-card::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.2);
opacity: 0;
transition: opacity 0.3s;
}

.feature-card:hover::before {
opacity: 1;
}

Usage with Tailwind:

{{div class="feature-card p-6 rounded-lg"}}
{{div class="text-white text-xl font-bold mb-2"}}
Premium Feature
{{/div}}
{{div class="text-white opacity-90"}}
Enhanced capabilities for power users
{{/div}}
{{/div}}

Best Practices

1. Use Design Tokens

Always reference CSS variables rather than hardcoding values:

Good:

.highlight {
background-color: var(--color-primary);
color: var(--color-on-primary);
}

Avoid:

.highlight {
background-color: #3b82f6;
color: white;
}

2. Semantic Class Names

Choose names that describe purpose, not appearance:

Good: .notification, .error-message, .primary-action

Avoid: .red-box, .big-text, .blue-button

3. Scope Your Styles

Prefix your custom classes to avoid conflicts:

.myapp-header { }
.myapp-navigation { }
.myapp-footer { }

4. Leverage Tailwind for Common Patterns

Use your custom CSS for unique designs and Tailwind for standard utilities:

{{div class="custom-gradient p-4 rounded-lg shadow-md"}}
Mixed approach: custom gradient + Tailwind utilities
{{/div}}

⚠️ Important Notice

This is under active development. The CSS variable naming, available tokens, and theming system may change in future updates.

Feedback welcome! If you have suggestions for:

  • Additional CSS variables that would be useful
  • Improvements to the theming system
  • Documentation clarifications
  • Support for your Use cases

Tokens

All available CSS custom properties (tokens) you can use in your custom stylesheets. These variables automatically adapt to the current theme (light/dark mode).

Layout

TokenDescriptionWhy It's Used
--border-radiusDefault border radius for UI elementsProvides consistent rounded corners throughout the interface (4px)

Background & Surfaces

TokenDescriptionWhy It's Used
--color-bgPrimary page or app backgroundSets the base background for the interface; all other layers stack on top
--color-on-bgDefault text color on the backgroundEnsures legibility against the main page/app background
--color-surfaceSurface background for cards, panels, modalsProvides a separate "layer" from the background for components, giving hierarchy and depth
--color-on-surfaceDefault text color on surfacesEnsures legible content on top of surface elements
--color-surface-variantSlightly elevated or alternate surfaceUsed for components like menus, popovers, or elevated cards to create contrast without changing the main surface
--color-on-surface-variantDefault text color on alternative surfacesEnsures legible content on variant surface elements

Text

TokenDescriptionWhy It's Used
--color-textGeneral purpose text colorDefault text color for body copy and general content

Borders & Dividers

TokenDescriptionWhy It's Used
--color-borderStandard border colorDefines boundaries between elements, used for inputs, cards, and structural divisions

Identity Colors

TokenDescriptionWhy It's Used
--color-primaryMain colorUsed for primary actions, buttons, links; central to the visual identity
--color-on-primaryText or icons on primary colorEnsures legibility when content is placed on primary-colored elements
--color-secondarySecondary colorProvides a complementary color for secondary actions or accents
--color-on-secondaryText or icons on secondary colorEnsures contrast when content is placed on secondary elements
--color-accentOptional tertiary or accent colorAdds visual interest or highlights without overriding primary/secondary
--color-on-accentText/icons on accent surfacesEnsures legibility on accent areas

State Colors

TokenDescriptionWhy It's Used
--color-infoInformational stateProvides a neutral or informative accent for messages or tips
--color-on-infoText/icons on informational surfacesEnsures legibility on info-colored elements
--color-successPositive state (confirmation, success)Used for success messages, badges, and notifications
--color-on-successText/icons on success surfacesEnsures contrast and readability
--color-warningWarning stateIndicates caution or important alerts
--color-on-warningText/icons on warning surfacesEnsures legibility on warning-colored elements
--color-errorError stateHighlights errors or destructive actions
--color-on-errorText/icons on error surfacesEnsures legibility for error messages or icons

Usage Examples

Basic usage:

.card {
background-color: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--border-radius);
padding: 1.5rem;
}

.card__title {
color: var(--color-primary);
}

.card__content {
color: var(--color-on-surface);
}

State-based styling:

.notification {
padding: 1rem;
border-radius: var(--border-radius);
}

.notification--info {
background-color: var(--color-info);
color: var(--color-on-info);
}

.notification--success {
background-color: var(--color-success);
color: var(--color-on-success);
}

.notification--warning {
background-color: var(--color-warning);
color: var(--color-on-warning);
}

.notification--error {
background-color: var(--color-error);
color: var(--color-on-error);
}

Color buttons:

.btn {
padding: 0.5rem 1rem;
border-radius: var(--border-radius);
border: none;
cursor: pointer;
}

.btn--primary {
background-color: var(--color-primary);
color: var(--color-on-primary);
}

.btn--secondary {
background-color: var(--color-secondary);
color: var(--color-on-secondary);
}