Skip to content

Accessibility

Theming that respects people

Theme Kit treats accessibility as a first-class runtime concern: WCAG contrast and CVD simulation, theme-aware focus rings, prefers-reduced-motion, color-scheme sync, and a scrollbar that stays theme-aware without breaking keyboard navigation.

1Live lab

Contrast ratios and color-vision-deficiency simulations computed from the active theme by @theme-kit/core — toggle the family above to see it re-run live.
Accessibility Lab

WCAG contrast & color vision, live

Every check below runs against the real accessibility toolkit in @theme-kit/core getContrastRatio, validateThemeContrast and simulateCVD.

Contrast checker

Pick any two colors and check WCAG AA/AAA compliance instantly.

foreground
background
Aaratio 17.85 : 1
AAAA largeAAAAAA large

This pair passes AA for normal text.

Live theme audit · theme-kit-default-light

validateThemeContrast() run against the active theme's semantic pairs.

foreground on background
18.37AA
cardForeground on card
19.00AA
popoverForeground on popover
19.00AA
primaryForeground on primary
5.41AA
secondaryForeground on secondary
15.11AA
mutedForeground on muted
5.61AA
accentForeground on accent
5.63AA
destructiveForeground on destructive
3.76AA

Color vision deficiency simulation

simulateCVD() of the active primary (#5b54e8).

Re-themes the site with every color run through simulateThemeForCVD() so you can check readability exactly as a user with that condition sees it.

Accessibility profiles

Ready-made high-contrast and large-text themes shipped in getBuiltInThemes().

High Contrast · Light

Maximum contrast for readability.

High Contrast · Dark

Maximum contrast on dark backgrounds.

Large Text · Light

Enlarged type on light backgrounds.

Large Text · Dark

Enlarged type on dark backgrounds.

The accessibility plugin — reacting to violations

createAccessibilityPlugin() audits every applied theme at WCAG AA and fires onViolation when a theme breaks the configured requirements. This is that callback, live.

Try it: a “low-contrast-demo” theme (white foreground on white background) is handed to the plugin's onAfterThemeChange hook — exactly what happens when such a theme is applied to a runtime.

2prefers-reduced-motion

The transition engine reads the OS preference and collapses animated theme changes to instant applies.
The flow
1prefers-reduced-motion: reduce
2transition engine checks the media query on every plan
3plan collapses to suppressTransition → instant apply
4no fade, no cross-fade, no View-Transition orchestration
core — reduced-motion in the transition engine
ts
1import { createThemeRuntime } from "@theme-kit/core";
2
3const runtime = createThemeRuntime({
4  themes,
5  defaultTheme: "light",
6  transition: {
7    enabled: true,
8    duration: 360,
9    easing: "cubic-bezier(0.4, 0, 0.2, 1)",
10    // The engine checks prefers-reduced-motion and collapses the
11    // transition plan to an instant apply for affected users.
12    preset: "smooth",
13  },
14});
Scoped themes inherit this |A ThemeScope transition goes through the same engine, so reduced-motion users get an instant scoped swap too.

3Focus rings & keyboard navigation

The focus ring is a semantic token, so every theme ships a visible, accessible focus indicator.
ring token

Focus styles reference --theme-color-ring — when a theme changes, the focus indicator re-styles with it.

keyboard

Theme pickers, toggles and scopes are plain interactive elements: tab to focus, Enter/Space to activate. Nothing in Theme Kit intercepts or reorders keyboard navigation.

4color-scheme & system preference

The effective mode is resolved against the OS and surfaced to the browser, not guessed.
  • system mode resolves against prefers-color-scheme server-side and in the bootstrap — the first paint already matches the OS.
  • color-scheme is set on <html> so native form controls and the default scrollbar match the theme.
  • A @media (prefers-color-scheme: dark) fallback ships for system mode so even a pre-JS paint is correct.
  • Contrast checking (getContrastRatio) and CVD simulation (simulateCVD) are core utilities you can run in CI on every theme.

5Scrollbar behavior

The optional overlay scrollbar stays theme-aware and never replaces native scroll behavior.
  • Keyboard and programmatic scrolling work exactly as with the native scrollbar — the overlay only draws.
  • The overlay colors come from semantic tokens, so it updates with the theme and respects high-contrast profiles.
  • When disabled, the native scrollbar is styled via color-scheme instead — still theme-aware, zero custom code.
Custom Scrollbar guide →

6Transition suppression

Any theme switch can be instant for a given update, per action or per scope.
runtime — one-off suppression
ts
1// For a single switch that must be instantaneous
2// (e.g. a user action on a big surface), suppress the
3// configured animation for that update only.
4runtime.store.set(runtime.registry.get("plum-dark")!, {
5  suppressTransition: true,
6});
Accessibility — Theme Kit