Skip to content

Theming

Customize colors, typography, and spacing using CSS variables.

Importing Styles

Default Styles

Import the stylesheet:

typescript
import '@vizel/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 '@vizel/core/components.css';

This includes only component styles without CSS variable definitions.


Theme Provider

Use the VizelThemeProvider to enable dark mode support:

tsx
import { VizelThemeProvider } from '@vizel/react';

function App() {
  return (
    <VizelThemeProvider 
      defaultTheme="system" 
      storageKey="my-app-theme"
    >
      <Editor />
    </VizelThemeProvider>
  );
}
vue
<script setup lang="ts">
import { VizelThemeProvider } from '@vizel/vue';
</script>

<template>
  <VizelThemeProvider defaultTheme="system" storageKey="my-app-theme">
    <Editor />
  </VizelThemeProvider>
</template>
svelte
<script lang="ts">
  import { VizelThemeProvider } from '@vizel/svelte';
</script>

<VizelThemeProvider defaultTheme="system" storageKey="my-app-theme">
  <Editor />
</VizelThemeProvider>

VizelThemeProvider Options

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

Using Theme State

tsx
import { useVizelTheme } from '@vizel/react';

function ThemeToggle() {
  const { theme, resolvedTheme, setTheme } = useVizelTheme();
  
  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>
  );
}
vue
<script setup lang="ts">
import { useVizelTheme } from '@vizel/vue';

const { theme, resolvedTheme, setTheme } = useVizelTheme();
</script>

<template>
  <select :value="theme" @change="setTheme($event.target.value)">
    <option value="light">Light</option>
    <option value="dark">Dark</option>
    <option value="system">System</option>
  </select>
</template>
svelte
<script lang="ts">
  import { getVizelTheme } from '@vizel/svelte';
  
  const theme = getVizelTheme();
</script>

<select value={theme.theme} onchange={(e) => theme.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

Vizel uses CSS custom properties (variables) for all visual styling. Override these to customize the appearance.

Theme Selectors

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

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

Color Variables

Primary Colors

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

Secondary Colors

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

Background & Foreground

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

UI Colors

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

State Colors

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

Example: Custom Colors

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

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

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

Typography Variables

Font Families

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

Font Sizes

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

Line Heights

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

Font Weights

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

Spacing Variables

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

Border Radius Variables

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

Shadow Variables

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

Transition Variables

VariableValue
--vizel-transition-fast100ms
--vizel-transition-normal150ms
--vizel-transition-slow300ms

Z-Index Variables

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

Component-Specific Variables

Editor

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

Images

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

Code Blocks

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

Mathematics

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

Portal

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

shadcn/ui Integration

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

css
:root {
  /* Map shadcn colors to Vizel */
  --vizel-primary: hsl(var(--primary));
  --vizel-primary-foreground: hsl(var(--primary-foreground));
  --vizel-background: hsl(var(--background));
  --vizel-foreground: hsl(var(--foreground));
  --vizel-border: hsl(var(--border));
  --vizel-muted: hsl(var(--muted));
  --vizel-muted-foreground: hsl(var(--muted-foreground));
  --vizel-accent: hsl(var(--accent));
  --vizel-accent-foreground: hsl(var(--accent-foreground));
  --vizel-destructive: hsl(var(--destructive));
  
  /* Map radius */
  --vizel-radius-sm: calc(var(--radius) - 4px);
  --vizel-radius-md: calc(var(--radius) - 2px);
  --vizel-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 flash:

typescript
import { getVizelThemeInitScript } from '@vizel/core';

// In your HTML head
const script = getVizelThemeInitScript('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-vizel-theme', resolved);
  })();
</script>

Next Steps

Released under the MIT License.