3.2 is current. 4.0 lands in March 2027 and removes Panel, InlineAlert and Stack.What it removes

Design system
  • Overview
  • Components
  • Tokens
  • Changelog
Propose a change

Tokens

Every value has a name

The full reference, the naming rules behind it, and what a designer does to propose a change. Two hundred and eighteen tokens, one source file, three published formats.

Reference

The token reference

Updated 4 September 2026Ingrid Halloran9 minutes

Every value in Bracket has a name. A colour that appears in a component and is not in this reference is a bug in that component.

Tokens exist in two layers. The primitive layer is a palette: --bk-blue-60, --bk-grey-10. Nothing in a component may read a primitive directly. The semantic layer says what a value is for: --bk-color-surface, --bk-color-text-muted. Components read only semantic tokens, which is what makes a theme a change of one file rather than a change of forty.

Naming

--bk-<category>-<role>-<modifier>

--bk-color-surface-raised
--bk-color-text-muted
--bk-space-4
--bk-radius-sm

Four rules, applied without exception:

  • The prefix is always bk. It is short because it is typed hundreds of times a day.
  • The category is one of color, space, size, text, radius, border, shadow, z.
  • The role says what the value is for, never what it looks like. --bk-color-text-muted, not --bk-color-text-grey.
  • The modifier is optional and always last: -raised, -hover, -inverse, -strong.

Colour

Semantic colours only. Each one resolves to a different primitive in light and dark, and both pairs are checked for contrast on every build.

  • --bk-color-surface — grey-00 light, grey-95 dark. The page behind everything.
  • --bk-color-surface-raised — grey-00 light, grey-88 dark. Cards, dialogs, menus. In light theme it is the same value as the page and is separated by a border instead.
  • --bk-color-surface-sunken — grey-04 light, grey-98 dark. Wells, table headers, code blocks.
  • --bk-color-text — grey-95 light, grey-06 dark. Body text, and the default for anything that does not say otherwise.
  • --bk-color-text-muted — grey-60 light, grey-45 dark. Descriptions, captions, disabled labels. Never for anything a person has to read to complete a task.
  • --bk-color-border — grey-16 light, grey-78 dark. Every one-pixel line in the system that is not a table rule.
  • --bk-color-border-strong — grey-32 light, grey-62 dark. Table rules and separators that carry meaning.
  • --bk-color-accent — blue-60 light, blue-48 dark. The single accent: links, focus ring, selection, the primary button.
  • --bk-color-accent-hover — blue-68 light, blue-40 dark. Hover and active states on accent surfaces.
  • --bk-color-danger — red-58 light, red-50 dark. Destructive actions and error text.
  • --bk-color-warning — amber-52 light, amber-46 dark. Warnings that are not errors.
  • --bk-color-success — green-52 light, green-44 dark. Confirmed, saved, passed.

There is one accent. Requests for a second have been declined three times; a system with two accents has no accent.

Space

A four-pixel scale, eleven steps. Every margin, padding and gap in every component is one of these values.

  • --bk-space-1 — 4px. Between an icon and its label.
  • --bk-space-2 — 8px. Inside a small control.
  • --bk-space-3 — 12px. Between related lines of text.
  • --bk-space-4 — 16px. The default gap, and the one to reach for first.
  • --bk-space-5 — 24px. Padding inside a card.
  • --bk-space-6 — 32px. Between cards.
  • --bk-space-7 — 48px. Between groups in a form.
  • --bk-space-8 — 64px. Between sections of a page.
  • --bk-space-9 — 96px. Between major blocks on a marketing page.
  • --bk-space-10 — 128px. Rare, and only at the top of a page.
  • --bk-space-11 — 160px. Used twice in the whole system.

There is no --bk-space-0: zero is zero.

Type

One family, Kalder Mono, at six sizes and two weights. The measure is wide on purpose: this system is for dense product interfaces and reference pages, not for magazines.

token             size    line    used for
--------------------------------------------------------------
--bk-text-xs      12px    16px    table metadata, badges
--bk-text-sm      14px    20px    secondary text, captions
--bk-text-base    16px    26px    body, and the default everywhere
--bk-text-lg      20px    28px    subheadings, lead paragraphs
--bk-text-xl      28px    34px    section headings
--bk-text-2xl     40px    46px    page headings, one per page

Weights are --bk-weight-regular (400) and --bk-weight-bold (600). There is no medium; adding one produced pairs nobody could tell apart in review.

Radius, border, elevation

token                  value          note
--------------------------------------------------------------
--bk-radius-none       0              tables, code blocks, the sidebar
--bk-radius-sm         2px            inputs, buttons, badges
--bk-radius-md         4px            cards, dialogs, menus
--bk-radius-full       9999px         avatars, and the one pill
--bk-border-width      1px            the only border width
--bk-shadow-raised     0 1px 2px      menus and dialogs, nothing else

Radii are small because the type is monospaced and a large radius next to a fixed-width grid reads as an accident. There is one shadow. Depth in Bracket is expressed with borders and surface colour; the shadow exists only for elements that float over content that is still visible underneath.

Consuming them

import '@kalder/bracket/tokens.css';

.summary {
  background: var(--bk-color-surface-raised);
  border: var(--bk-border-width) solid var(--bk-color-border);
  border-radius: var(--bk-radius-md);
  padding: var(--bk-space-5);
}

The same values are published as @kalder/bracket/tokens.json for anything that is not CSS, and as a Figma variable collection generated by the same build. All three come from one source file, tokens/source.yaml, and cannot drift apart.

Naming

Why the names are what they are

The questions that come back every time somebody reads the table for the first time.

  • Why not name colours after the colour?

    Because --bk-color-text-grey is a lie in dark theme, where it is nearly white. A name that describes appearance has to be renamed the first time a theme is added, and renaming a token costs a major release.

  • Why a number scale for space and not small, medium, large?

    Words run out. We had small, medium, large, then x-small and xx-large, and then an argument about what came between medium and large. Numbers extend without a meeting.

  • Why is there no --bk-space-0?

    Zero has a name already and it is 0. A token for it suggests it might one day be something else, which it will not.

  • Why is the prefix bk and not bracket?

    Length. The prefix is typed more often than any other part of the system. Two letters were chosen over seven after a week of using both.

  • Why only one accent colour?

    A second accent is only meaningful if it means something different, and no one proposing it has been able to say what. Two accents in a product read as an inconsistency rather than a choice.

  • Can I add a token in my own product?

    Yes, with your own prefix. A product token called --shipyard-color-lane-active is fine and is your responsibility. A custom property starting with --bk- that Bracket did not define will be overwritten by a release without warning.

Contributing

How to propose a change

Updated 4 September 20266 minutes

A token is a decision that forty people have to live with, so the process is slower than it looks necessary. It has four steps and usually takes about three weeks.

1. Write down the case

Open an issue with three things: what you are trying to build, which existing token you tried, and why it was wrong. An issue that names a value rather than a problem is sent back. --bk-color-surface-subtle is not a case; a settings panel that needs a third surface level, with a screenshot, is.

The tracker keeps every declined proposal with its reason, and about half of new proposals are answered with a link to one of them.

2. Build it locally first

Override the custom property in your own product and use it for a fortnight. Most proposals stop here, either because the existing token turned out to be fine or because the new one looked wrong once it was in a real screen next to everything else.

Bring back whatever you learned, including the version where it did not work.

3. Review at office hours

Thursdays, 15:00 to 16:00. Ten minutes: the case, the screenshot, and the two months of use. Present it yourself; a proposal presented by a maintainer on your behalf always loses detail.

The questions asked are the same four every time, so prepare them:

  • What breaks if this is not added?
  • Which existing token is it closest to, and why is that one not enough?
  • Would two other products use it, or is this one screen?
  • What is it called, and does the name survive the next theme?

4. Decision, in writing

Both maintainers must agree. The decision is written in the issue, with reasons, within a week of the review. A no stays in the declined list so that the same proposal can be answered with a link rather than argued a second time.

A yes ships in the next minor release. New tokens are additive, so they never wait for a major.

Changing an existing token

Harder, and rarer. Changing what a token resolves to changes every product at once, so it happens only in a major release, and only with a screenshot of the before and after in at least three products.

Renaming a token is the same thing as removing one: the old name is kept for a full major cycle, the console warns in development, and a codemod does the rename.

Who decides

Two maintainers, both part-time on Bracket.

  • Ingrid Halloran — tokens, themes, contrast. Has the final word on anything in the colour table.
  • Tobias Renn — components, the React package, releases. Has the final word on props and on what ships.

They disagree in public on the tracker rather than in private, which is slower and has been worth it every time. Where they cannot agree, nothing changes, and the proposal stays open.

Design system

Bracket is the design system of Kalder Industries. Published openly so that contractors and sister teams build against the same decisions.

System

  • Overview
  • Components
  • Tokens
  • Changelog

Elsewhere

  • Package
  • Figma library
  • Issue tracker
  • Office hours

Legal

  • Legal notice
  • Privacy
Kalder Industries. The package is licensed for use by Kalder teams and contracted suppliers; the documentation may be read by anyone.