Knit UI
GitHub

Variants & colors

variant decides how a component applies the active theme's colour ramp. theme decides which ramp. No component takes a color prop.

Every visual variant side by side, at the default size.

Loading example…

VariantsSourceStorybook

The variants

VariantFillTextBorder
filledsolid accent ($color9)contrast (white or near-black)none
lighttinted accent ($color3)accent ($color11)none
outlinetransparentaccentaccent
subtletransparent, tint on hoveraccentnone
defaultneutral surfaceneutral textneutral border
whitewhiteaccentnone
transparentnone, no hoveraccentnone
gradientthe gradient propcontrastnone

Interactive components resolve these through controlColorVariant; static surfaces (Alert, Badge, Pill) use surfaceColorVariant, which is the same ladder without the hover/press states. Both live in one table — internal/variant-colors.ts — which is the colour twin of controlMetrics.

Recolouring with theme

<Group>
  <Button>default accent</Button>
  <Button theme="red">destructive</Button>
  <Button theme="green">confirm</Button>
</Group>

theme swaps the ramp the variant reads from, so all eight variants keep working and every nested component inherits it. That is why there is no color prop: a color would only tint one surface, while theme recolours the whole subtree coherently — text, border, hover, press and focus ring together.

The palette ramp follows the active theme — same component, different accent.

Loading example…

ThemedSourceStorybook

The ramp

A theme is a 12-step ramp, addressed as $color1$color12:

StepsUsed for
1–2app and subtle surfaces
3–5component backgrounds — normal, hover, press
6–8borders — normal, hover, focus
9–10solid accent fills, and their hover
11–12text on a subtle background, and high-contrast text

Semantic aliases sit on top: $background, $backgroundHover, $borderColor, $borderColorFocus, $color, $placeholderColor. Prefer the alias where one exists — it survives a theme redesign that renumbers the ramp.

Which components use the ladder

Button, ActionIcon, Alert, Avatar, Badge, Pill, ThemeIcon, CloseButton and Chip derive their colours from the variant table.

Some components — Stepper, Switch, Table, Tabs — drive colour from the raw ramp instead, because their chrome does not decompose into "fill, text, border". That is allowed, and their pages state it.

Building on it

The ladders are exported so your own controls can match:

import {
  VARIANT_FILL,
  VARIANT_FOREGROUND_EMPHASIS,
  VARIANT_INTERACTION,
  type VariantKey,
} from "@knitui/components/control-system";

Spread them onto a styled() frame's variants rather than re-deriving colours — that is how @knitui/media's player chrome stays visually identical to the kit's own controls.

See also: Color & themes, Gradients.