Skip to content
Noksha UIv0.1
Colour theme

Getting started

Theming

Three layers of plain CSS custom properties. No ThemeProvider is required for any of it.

The three layers

LayerExampleChanges with theme?
1 · Primitive--noksha-violet-500No — 11 generated steps per hue
2 · Semantic--noksha-bg-surfaceYes — the only layer that does
3 · Component--noksha-button-h-mdNo — derived from the scales

Components only ever read layers 2 and 3, never layer 1. That is what makes a new theme a forty-line CSS block instead of a fork.

Rebranding

One declaration and the whole library follows — every tone, every hover state, both modes.

:root {
  --noksha-brand: #0EA5E9;
}

Why OKLCH, not HSL

In HSL, hsl(60 100% 50%) and hsl(240 100% 50%) claim the same lightness but differ by roughly ten times in perceived brightness — so an HSL scale needs hand-tuning for every hue. In OKLCH, L is perceived lightness, so one lightness ramp works for every hue and the scales below were generated, not designed.

Accent#6D4AFF
50100200300400500600700800900950
Danger#E5484D
50100200300400500600700800900950
Success#30A46C
50100200300400500600700800900950
Warning#F1A10D
50100200300400500600700800900950

Every step is gamut-mapped into sRGB by lowering chroma only, so the lightness ramp holds exactly regardless of hue. Foregrounds are picked per step by relative luminance, and the build fails if a pairing cannot reach 4.5:1.

Dark mode

Dark applies through three selectors so a class-based setup, an attribute-based one, and plain system preference all work without configuration.

/* Light is the :root default. */
:root { --noksha-bg-canvas: oklch(0.995 0.003 283.66); }

/* Dark applies through three selectors, so every setup works. */
.dark,
[data-theme='dark'] { --noksha-bg-canvas: oklch(0.18 0.008 283.66); }

@media (prefers-color-scheme: dark) {
  :root:not(.light):not([data-theme='light']) { … }
}

Add themeScript() to your <head> to avoid a flash on first paint — see Installation.

Retuning the scales

ScaleVariableEffect
Radius--noksha-radius-base0 is sharp, 0.5rem is soft.
Density--noksha-density0.875 compact · 1 default · 1.125 comfortable. Drives every control height and pad.
Motion--noksha-duration-*All animation reads these; prefers-reduced-motion zeroes them globally.
Typography--noksha-text-*Fluid clamp() steps, so headings scale with the viewport.

More than one brand

Multi-tenant apps scope a second palette to a selector and swap one attribute at runtime.

import { emitThemeOverride } from '@noksha-ui/tokens';

// A second brand costs one scoped block, not a fork.
emitThemeOverride('[data-brand="acme"]', { brand: '#F97316' });