Fragiola UI
Architecture

Theming

Fragiola's colour system is built on **palettes**: sets of six roles applied

Fragiola's colour system is built on palettes: sets of six roles applied by class. Components read roles, never colours.

The six roles

rolewhat it is
basethe color of this palette — background or fill
softsubtle background — alert, badge, hover, field surface
linestroke
contrastcontent on base
accentcontent on a foreign background or on soft
ringinteraction highlight — focus, active

The palette class declares the six custom properties and paints nothing. Components paint explicitly with bg-palette-base, text-palette-contrast, and so on.

The number of palettes is free; the number of roles is not

If something does not fit, create another palette. Two background levels on a surface are two palettes, not a seventh role. A token that is always derived and never overridden is a derivation, not a role — --color-palette-base-hover is computed from base in @theme with an escape hatch, because no palette ever overrode it.

Every palette declares all six

Custom properties inherit. A palette that omits a role picks it up from whatever ancestor declared it — silently, across unrelated scopes. "Optional token" does not exist in an inheritance-based system. This is why ring, the one people forget, is mandatory: an omitted ring inherits from an ancestor, and that is how an invalid field inside a feature ended up with a red border and a purple focus ring.

Scoping

A palette is scoped by class, so any subtree can carry its own. palette-danger on a button tints that button; palette-raised on a card changes the whole card's surface. Adding a colour is a new palette, not a new token everywhere — destructive went from 132 occurrences to 10.

Never mix palettes

A palette that borrows neutrals from one place and colour from another exists only to fit one case, and the next case will ask for another exception. The tell: a role with no coherent source. If you need a neutral surface with a coloured focus ring, create a surface-* palette — that is what they are for.

Secondary text

The most-used token in the shadcn baseline (muted-foreground, 44 occurrences) maps to a role Fragiola deliberately lacks. The settled value is text-palette-accent/85 — it clears AA (4.5:1) on every neutral surface in both themes. Apply it uniformly, including to placeholders. See AGENTS.md for the measurement.

Chart series are not palettes

No role describes "the third series", and reusing danger as series 4 breaks its meaning. Chart colours live outside the contract, in their own ordered set; their ordering is what guarantees colourblind separation. Only the derived ordinal ramp is themeable.

On this page