Skip to content
Development
Skill

/theming

Use when building a theme or theming system for an interface. Covers token architecture, dark mode, contrast preservation across themes, and generating a coherent palette from a seed colour. Trigger on "add dark mode", "contrast breaks in dark mode", "white-label this app",

From plugin
claude-skills-collection
34137 skills

Claude Code

$ npx -y skills add nimadorostkar/Claude-Skills-collection --skill theming --agent claude-code

SKILL.md

theming.SKILL.md
name: theming
description: Use when building a theme or theming system for an interface. Covers token architecture, dark mode, contrast preservation across themes, and generating a coherent palette from a seed colour. Trigger on "add dark mode", "contrast breaks in dark mode", "white-label this app", "generate a palette from our brand color". Do not use for a component library's full token and API architecture — see the design-systems skill.
metadata:
  category: design
  version: 1.0.0
  tags: [theming, dark-mode, tokens, color, css]

Theming

Purpose

Build themes that remain readable and coherent when switched. Dark mode is not an inversion; a palette that works on white will not work on black without being redesigned, and inverting it produces the vibrating, exhausting interfaces that dark mode is criticized for.

When to Use

  • Adding dark mode to an interface.
  • Building a multi-theme or white-label system.
  • Generating a palette from a brand colour.
  • Fixing a theme where contrast breaks in one mode.

Capabilities

  • Semantic token architecture that supports theme switching.
  • Dark-mode design (as opposed to inversion).
  • Palette generation with perceptually uniform colour spaces.
  • Contrast verification across every theme.
  • Respecting system preference and user override.

Inputs

  • The base palette or the seed colour.
  • The themes required: light, dark, high-contrast, per-brand.
  • Accessibility requirements.

Outputs

  • Semantic tokens that resolve differently per theme.
  • Every theme passing contrast requirements.
  • A switch that respects the system preference and remembers an override.

Workflow

1. **Build on semantic tokens** — Components reference `--color-surface`, never `--grey-900`. Only the semantic layer changes between themes; components do not change at all. 2. **Design the dark theme, do not invert it** — Pure black is harsh and causes halation with white text. Use a very dark grey. Desaturate the accents: a colour that is vivid on white is glaring on dark. 3. **Preserve the contrast relationships** — Verify every text-on-surface pairing in every theme. A ratio that passes in light frequently fails in dark. 4. **Work in a perceptual colour space** — OKLCH lightness is perceptually uniform; HSL's is not. Generating a scale in HSL produces steps that look wrong even though the numbers are even. 5. **Respect the system, allow an override** — Default to `prefers-color-scheme`, and store an explicit user choice. 6. **Handle elevation** — In light mode, elevation is a shadow. In dark mode, shadows are invisible; elevation is a lighter surface.

Best Practices

  • Pure black (`#000`) with pure white text causes halation — the text appears to vibrate. Every well-designed dark theme uses a dark grey around `#121212` to `#1a1a1a`.
  • A saturated brand colour that looks correct on white will glow uncomfortably on a dark background. Reduce its saturation and raise its lightness for the dark theme.
  • Elevation in dark mode is conveyed by making a surface *lighter*, not by adding a shadow. A shadow on a dark background is invisible.
  • Test every theme against the contrast requirements. This is the single most common theming failure, and it is entirely mechanical to check.
  • A theme toggle that does not persist is a bug that users notice on every page load.
  • Do not animate the theme transition on colours. It looks impressive once and is irritating thereafter.

Examples

**Semantic tokens, with the dark theme designed rather than inverted:**

:root {
  /* Light: surfaces are near-white; elevation is a shadow. */
  --color-bg:              oklch(99% 0 0);
  --color-surface:         oklch(100% 0 0);
  --color-surface-raised:  oklch(100% 0 0);
  --shadow-raised:         0 1px 3px oklch(0% 0 0 / 0.12);

  --color-text:            oklch(20% 0.01 250);
  --color-text-muted:      oklch(50% 0.01 250);
  --color-border:          oklch(90% 0.005 250);

  --color-action:          oklch(55% 0.20 255);   /* the brand blue */
  --color-action-text:     oklch(100% 0 0);
}

[data-theme="dark"] {
  /* Not an inversion. #121212-equivalent, not black: pure black causes
     halation with white text. */
  --color-bg:              oklch(15% 0.005 250);
  --color-surface:         oklch(19% 0.005 250);

  /* Elevation in dark mode is a LIGHTER surface. A shadow would be invisible. */
  --color-surface-raised:  oklch(24% 0.006 250);
  --shadow-raised:         none;

  --color-text:            oklch(93% 0.005 250);  /* not pure white */
  --color-text-muted:      oklch(65% 0.008 250);
  --color-border:          oklch(30% 0.008 250);

  /* The brand blue, desaturated and lightened. The light-mode value
     (55% 0.20) glows uncomfortably against a dark surface. */
  --color-action:          oklch(68% 0.14 255);
  --color-action-text:     oklch(15% 0.005 250);
}

**Verifying contrast mechanically, in every theme:**

const PAIRS = [
  ["--color-text",       "--color-surface", 4.5],   // body text: AA
  ["--color-text-muted", "--color-surface", 4.5],
  ["--color-action",     "--color-surface", 3.0],   // UI component boundary
  ["--color-action-text","--color-action",  4.5],   // text on the button
] as const;

for (const theme of ["light", "dark", "high-contrast"] as const) {
  for (const [fg, bg, required] of PAIRS) {
    const ratio = contrastRatio(resolve(fg, theme), resolve(bg, theme));
    if (ratio < required) {
      throw new Error(
        `Theme "${theme}": ${fg} on ${bg} is ${ratio.toFixed(2)}:1, ` +
        `below the required ${required}:1.`
      );
    }
  }
}

Notes

  • OKLCH is worth adopting specifically because its lightness channel is perceptually uniform. Generating a ten-step scale by evenly spacing HSL lightness produces steps that appear badly uneven; the same in OKLCH does not.
  • The "elevation is a lighter surface" rule is the single detail that most distinguishes a well-designed dark theme from an inverted light one.

-

Read more
@nimadorostkar
Ships withclaude-skills-collection

A curated library of 137 production-grade skills for Claude and other AI coding agents. Every skill follows one structure, speaks with one voice, and earns its place by changing what the agent does.

Stars on GitHub

Momentum

stars in total
34
Star history of nimadorostkar/Claude-Skills-collection on GitHub, a chart by star-history.com

Other skills on claude-skills-collection.

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills12d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react3d252k
@facebook@facebookInstall Skill

Questions about theming.

Which coding agents can use theming?
theming installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.