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
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.
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 backgroundcardForeground on cardpopoverForeground on popoverprimaryForeground on primarysecondaryForeground on secondarymutedForeground on mutedaccentForeground on accentdestructiveForeground on destructiveColor 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().
Maximum contrast for readability.
Maximum contrast on dark backgrounds.
Enlarged type on light backgrounds.
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
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});ThemeScope transition goes through the same engine, so reduced-motion users get an instant scoped swap too.3Focus rings & keyboard navigation
Focus styles reference --theme-color-ring — when a theme changes, the focus indicator re-styles with it.
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
systemmode resolves againstprefers-color-schemeserver-side and in the bootstrap — the first paint already matches the OS.color-schemeis set on<html>so native form controls and the default scrollbar match the theme.- A
@media (prefers-color-scheme: dark)fallback ships forsystemmode 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
- 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-schemeinstead — still theme-aware, zero custom code.
6Transition suppression
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});