Skip to content

Storybook Theming Plan

Here’s the updated Markdown plan/prompt, now including:

  • Light + Dark mode support
  • Theme aligned with sven-relijveld.com design system
  • Scalable structure (tokens, reuse, consistency)

Storybook Custom Theme Implementation Plan (Dual Mode + Website Alignment)

🎯 Objective

Implement a custom Storybook theme system that:

  • Supports both light and dark mode
  • Matches the design system of sven-relijveld.com
  • Ensures visual consistency across product and Storybook
  • Uses shared design tokens (colors, typography, spacing where applicable)

🧭 High-Level Strategy

Instead of hardcoding values directly in a single theme:

  1. Extract design tokens from sven-relijveld.com
  2. Create two themes:
    • lightTheme
    • darkTheme
  3. Allow Storybook to:
    • Toggle between light/dark
    • Default to system or preferred mode

🧩 Implementation Steps


1. Extract Design Tokens (Critical Step)

Analyze sven-relijveld.com and define:

🔑 Required Tokens

js
// .storybook/tokens.js
export const tokens = {
  colors: {
    primary: '<extract>',
    secondary: '<extract>',
    backgroundLight: '<extract>',
    backgroundDark: '<extract>',
    textLight: '<extract>',
    textDark: '<extract>',
    border: '<extract>',
    accent: '<extract>',
  },

  typography: {
    fontBase: '<extract>',
    fontCode: 'monospace',
  },

  radius: {
    default: 4,
    input: 2,
  },
};

Important: These values must match the website exactly (inspect CSS, Tailwind config, or design system).


2. Create Light Theme

Path:

.storybook/lightTheme.js
javascript
import { create } from 'storybook/theming/create';
import { tokens } from './tokens';

export default create({
  base: 'light',

  // Typography
  fontBase: tokens.typography.fontBase,
  fontCode: tokens.typography.fontCode,

  // Branding
  brandTitle: 'Sven Relijveld UI',
  brandUrl: 'https://sven-relijveld.com',
  brandImage: '/logo-light.png',
  brandTarget: '_self',

  // Colors
  colorPrimary: tokens.colors.primary,
  colorSecondary: tokens.colors.secondary,

  // UI
  appBg: tokens.colors.backgroundLight,
  appContentBg: tokens.colors.backgroundLight,
  appPreviewBg: tokens.colors.backgroundLight,
  appBorderColor: tokens.colors.border,
  appBorderRadius: tokens.radius.default,

  // Text
  textColor: tokens.colors.textLight,
  textInverseColor: tokens.colors.backgroundLight,

  // Toolbar
  barBg: tokens.colors.backgroundLight,
  barTextColor: tokens.colors.textLight,
  barSelectedColor: tokens.colors.primary,

  // Forms
  inputBg: '#ffffff',
  inputBorder: tokens.colors.border,
  inputTextColor: tokens.colors.textLight,
  inputBorderRadius: tokens.radius.input,
});

3. Create Dark Theme

Path:

.storybook/darkTheme.js
javascript
import { create } from 'storybook/theming/create';
import { tokens } from './tokens';

export default create({
  base: 'dark',

  // Typography
  fontBase: tokens.typography.fontBase,
  fontCode: tokens.typography.fontCode,

  // Branding
  brandTitle: 'Sven Relijveld UI',
  brandUrl: 'https://sven-relijveld.com',
  brandImage: '/logo-dark.png',
  brandTarget: '_self',

  // Colors
  colorPrimary: tokens.colors.primary,
  colorSecondary: tokens.colors.secondary,

  // UI
  appBg: tokens.colors.backgroundDark,
  appContentBg: tokens.colors.backgroundDark,
  appPreviewBg: tokens.colors.backgroundDark,
  appBorderColor: tokens.colors.border,
  appBorderRadius: tokens.radius.default,

  // Text
  textColor: tokens.colors.textDark,
  textInverseColor: tokens.colors.backgroundDark,

  // Toolbar
  barBg: tokens.colors.backgroundDark,
  barTextColor: tokens.colors.textDark,
  barSelectedColor: tokens.colors.accent,

  // Forms
  inputBg: '#1e1e1e',
  inputBorder: tokens.colors.border,
  inputTextColor: tokens.colors.textDark,
  inputBorderRadius: tokens.radius.input,
});

4. Enable Theme Switching in Storybook

Storybook itself does not automatically toggle themes, so implement switching logic.

Option A — Static default (simple)

javascript
// .storybook/manager.js
import { addons } from 'storybook/manager-api';
import lightTheme from './lightTheme';

addons.setConfig({
  theme: lightTheme,
});

Use storybook-dark-mode addon.

Install

bash
npm install storybook-dark-mode

Configure

javascript
// .storybook/preview.js
import { themes } from '@storybook/theming';

export const parameters = {
  darkMode: {
    current: 'light',
    dark: require('./darkTheme').default,
    light: require('./lightTheme').default,
  },
};

✅ Expected Outcome

  • Storybook UI supports light and dark mode
  • Theme matches sven-relijveld.com branding exactly
  • Logo updates per theme (light/dark assets)
  • Colors, typography, and UI are consistent with the website
  • Developers experience visual parity with production UI

🧪 Validation Checklist

  • [ ] Light theme matches website
  • [ ] Dark theme matches website
  • [ ] Theme switches correctly via addon
  • [ ] Typography matches website fonts
  • [ ] Logo adapts per theme
  • [ ] No hardcoded colors outside tokens
  • [ ] UI contrast meets accessibility standards

⚠️ Constraints

  • base must be explicitly set (light or dark)
  • Tokens must be single source of truth
  • No duplication of color values across files
  • Avoid inline values unless necessary

🚀 Optional Enhancements

  • Sync tokens with:
  • Tailwind config
  • Design system JSON
  • Auto-detect system theme (prefers-color-scheme)
  • Add Storybook toolbar toggle UI
  • Export tokens for reuse in components

🧠 Agent Notes

  • Treat Storybook as a mirror of production UI
  • Prioritize consistency over styling experimentation
  • Ensure maintainability via tokens
  • The closer this matches the real site, the better the dev experience

End of Plan