Skip to content
Español

Navigate

Type to search. Press Escape to close.

    Foundations

    Tokens and themes

    Every visual decision is a custom property prefixed --iv-, generated from one JSON source. Override any of them on :root or on a scope; nothing needs recompiling.

    :root {
      --iv-color-primary: #4338CA;      /* your brand */
      --iv-color-on-primary: #FFFFFF;
      --iv-radius-md: 0.25rem;
    }
    .checkout { --iv-button-radius: var(--iv-radius-full); }  /* component-local */

    Themes

    data-iv-theme accepts light (default when absent), dark and system. Scopes nest and the nearest explicit value wins; system follows prefers-color-scheme without JavaScript or storage.

    Nested scopesfixtures/theme/nested.htmlOpen alone — Nested scopes
    <div class="iv-grid iv-u-gap-4 iv-u-grid-cols-1 iv-u-md-grid-cols-3">
      <section class="iv-card" data-iv-theme="light"><div class="iv-card__body"><h3 class="iv-card__title">Light scope</h3><button class="iv-button iv-button--primary" type="button">Primary</button></div></section>
      <section class="iv-card" data-iv-theme="dark"><div class="iv-card__body"><h3 class="iv-card__title">Dark scope</h3><button class="iv-button iv-button--primary" type="button">Primary</button>
        <section class="iv-card iv-u-mt-4" data-iv-theme="system"><div class="iv-card__body"><p class="iv-u-m-0">System inside dark follows the OS.</p></div></section>
      </div></section>
      <section class="iv-card" data-iv-theme="system"><div class="iv-card__body"><h3 class="iv-card__title">System scope</h3><button class="iv-button iv-button--primary" type="button">Primary</button></div></section>
    </div>

    The optional theme module adds getTheme(), setTheme(theme, { persist }), resolveTheme() and restoreTheme(), and dispatches iv:themechange on document. Persistence is opt-in. To avoid a flash before the stored theme applies, add a tiny inline script in <head>; with a strict CSP allow it by hash or nonce.

    Semantic colours

    TokenLightDark
    --iv-color-bg#FFFFFF#04070F
    --iv-color-surface#F5F7FC#070D1C
    --iv-color-surface-raised#FFFFFF#0C1330
    --iv-color-text#0B1230#EEF2FB
    --iv-color-text-muted#4F5B7A#A8B3CC
    --iv-color-border#D3DAEA#33406A
    --iv-color-border-strong#6B7896#6B7896
    --iv-color-primary#1D4FC4#66B1FF
    --iv-color-on-primary#FFFFFF#06122B
    --iv-color-primary-hover#1A3FA8#8FC6FF
    --iv-color-primary-active#172F7A#3D94FF
    --iv-color-primary-subtle#EAF4FFrgb(102 177 255 / 0.12)
    --iv-color-accent#0B6B8A#73DFFF
    --iv-color-on-accent#FFFFFF#06122B
    --iv-color-success#4F7A12#8BBF3A
    --iv-color-on-success#FFFFFF#06122B
    --iv-color-success-subtle#F1F8E4rgb(139 191 58 / 0.12)
    --iv-color-danger#C22E26#FF9AA4
    --iv-color-on-danger#FFFFFF#06122B
    --iv-color-danger-subtle#FFF1F0rgb(255 154 164 / 0.12)
    --iv-color-warning#8F5C00#FBBF24
    --iv-color-on-warning#FFFFFF#06122B
    --iv-color-warning-subtle#FFF8E6rgb(251 191 36 / 0.12)
    --iv-color-info#3D47C2#8B95FF
    --iv-color-on-info#FFFFFF#06122B
    --iv-color-info-subtle#EEF0FFrgb(139 149 255 / 0.12)
    --iv-color-focus#1D4FC4#73DFFF
    --iv-color-overlayrgb(11 18 48 / 0.55)rgb(2 5 12 / 0.78)
    --iv-color-hover-surfacergb(11 18 48 / 0.04)rgb(230 240 255 / 0.05)
    --iv-color-primary-borderrgb(29 79 196 / 0.55)rgb(102 177 255 / 0.5)

    Contrast targets: text 4.5:1, controls and focus 3:1 on their surfaces. The values above were checked against the WCAG formula; results are re-measured on each release.

    The expressive layer

    Six tokens added in v0.6. They name the recipes the polish pass had repeated by hand across a dozen modules — a shadow, a hover tint, a brand edge, a focus halo and two letter spacings — so every module now reads the same value from one place. Nothing changed visually when they landed: they are names for what was already drawn.

    TokenLightDarkWhere it is used
    --iv-shadow-ambient0 2px 10px rgb(11 18 48 / 0.10)0 0 1px 1px #1C2544, 0 2px 10px rgb(0 0 0 / 0.5)Resting elevation of card, wrapped table, alert, accordion and button. One token instead of five recipes.
    --iv-color-hover-surfacergb(11 18 48 / 0.04)rgb(230 240 255 / 0.05)Pointer tint on card, dialog and drawer footers, tabs and the picker field. Table and menu rows keep the brand tint of primary-subtle.
    --iv-color-primary-borderrgb(29 79 196 / 0.55)rgb(102 177 255 / 0.5)Brand outline: secondary button, field hover, pagination, and anywhere an edge should read as the brand.
    --iv-focus-halo0 0 2px 3px rgb(29 79 196 / 0.35)0 0 3px 2px rgb(102 177 255 / 0.32)The glow that accompanies the focus ring on fields, buttons, pagination, breadcrumbs, stepper markers and the navbar toggle. Always next to the outline, never instead of it.
    --iv-tracking-tight-0.011em-0.011emLetter spacing of card, dialog, drawer and stat titles.
    --iv-tracking-caps0.06em0.06emLetter spacing of small caps: table headers, fieldset legends, megamenu and palette headings, stat labels.

    The two colours also appear in the table above, because they are semantic colours like any other. All six are plain custom properties: override them on :root or on a scope and every component that reads them follows.

    Scales

    FamilyTokens
    Space--iv-space-0 … 16 (0.25rem steps up to 1.5rem, then 2, 2.5, 3, 4rem)
    Type--iv-text-xs … 4xl, --iv-leading-*, --iv-weight-*, --iv-font-sans|mono
    Shape--iv-radius-sm|md|lg|full, --iv-border-width, --iv-shadow-1|2|3
    Focus--iv-focus-width, --iv-focus-offset, --iv-color-focus
    Motion--iv-motion-fast|base|slow (120/180/220 ms; 0 ms under reduced motion), --iv-ease-out
    Layers--iv-z-dropdown|drawer|dialog|toast
    Measures--iv-measure (68ch), --iv-container-max (75rem), --iv-content-max (90rem)
    Breakpointssm 30em · md 48em · lg 64em · xl 80em · 2xl 90em. Resolved at build time; not available as custom properties inside media queries.