The same buttons, link, field and form on the page, in theme islands and
on a band the application paints, each measured live: Aa
is the text against the fill it sits on (4.5:1), ◎ is the
focus line against what surrounds it (3:1). The form row also carries a
combobox and a date picker on their token bridges. Switch theme or OS
scheme and the numbers follow.
The switch paints the core recipe on every sample at once. A theme that
restyles field focus (gradient, material) shows
its own line on real keyboard focus: press Tab.
Three intentions, three tools
Change the whole visual context
data-theme on the section, footer or card. Every token
recomputes: surfaces, text, fields, validation, intents, focus and
native controls. In a branded app, light and
dark are the scheme roles of your brand.
Change one component's treatment
A variant (.solid, .soft,
.outline, .surface) or a component hook.
Just paint a special background
Application CSS: --surface-solid under
--surface. Neutral ink and filled buttons read on it;
intent ink and forms keep the page palette, so they stay out.
Every context, same samples
Red marks a pair under its threshold. Every island passes, form, combobox
and date picker included. On the painted band, the intent variants that
put their ink on it (outline, ghost, link) fail: nothing tunes an intent
for a surface the application paints. That is why the band carries no
form, and why a band that needs either is an island.
Joined fields need zero adaptation
Each segment draws its focus line inside its own border box, so
.join only handles corners, shared edges, stretch and
stacking — no rule in join.css mentions focus. A field
wrapped one level deep (.input-icon, a combobox, a date
picker) is supported generically: the wrapper takes the group corners,
the field inherits them and fills the stretched height. Tab through the
segments, or show every line at once: none overlaps a neighbour.
Two fields and an action
Addon, field, action
€
Select and field
Icon field and icon action
Invalid segment
Combobox and action
Date picker and action
Focus: one token, two surfaces
Every indicator is a solid --focus-ring-width line in
--focus — inset on fields, offset on actions. It never follows
an intent or a local surface, so the theme must keep --focus
at 3:1 against both surfaces a line can land on.
bun run report:theme-contrast prints both pairs per theme.
Which one?
A dark (or light) footer, navbar, section or card:
data-theme="dark" (or light, or your theme) on
it. Forms, intents and widgets inside all follow.
A painted band with neutral content and filled actions only:
application CSS, as in the last context above.
A plain .card inside any band stays a normal card and resets
the context for its content.