Colors 149
Every token in 1. Colors, Light Mode. Semantic roles only — the 385 tokens in 7. _Primitive are excluded by the primitive gate and must never be referenced directly.
Text 20
Background 33
Border 17
Icon 19
Charts 12
Opacity 18
Alpha 30
Corrections applied to the export
These five depart from the raw export for a documented accessibility reason. The export value and the measurement are kept so the deviation is never silent.
| Figma variable | Used | Why |
|---|
Roles added on top of the export
The export leaves these undefined, and every one covers a need that would otherwise fall back to a raw value.
| Token | Value | Why |
|---|---|---|
--text-on-error-solid | #ffffff | on-solid content; text-alt flips per mode, bg-error-solid does not |
--text-on-warning-solid | #0a0a0a | white on bg-warning-solid measures 2.15:1 |
--text-on-success-solid | #0a0a0a | on-solid content for bg-success-solid |
--text-on-info-solid | #ffffff | on-solid content for bg-info-solid |
--bg-error-solid_hover | #b91c1c | error/700 — the export defines no error hover; the solid fill deepens on hover |
--bg-error-solid_press | #991b1b | error/800 — deepens again on press, two steps below the resting error/600 |
--bg-error_press | #fecaca | error/200 — press step for the soft error surface, above bg-error-secondary |
--focus-ring-width | 3px | shadcn-style ring: one soft band hugging the border, no offset gap |
--focus-ring | var(--alpha-neutral-accent-20) | focus band — the export's own neutral accent at 20% |
--focus-ring-error | var(--alpha-error-accent-20) | focus band for an invalid control |
--border-control | #8d8d8d | interactive control boundary; WCAG 1.4.11 needs 3:1 |
--border-focus-ring | #171717 | focus treatment named in components §10.3 but untokenised |
--shadow-card | 0 4px 24px rgba(10,10,10,.05) | elevation must arrive through a named token |
--shadow-evidence | 0 24px 60px rgba(10,10,10,.14) | elevation must arrive through a named token |
--ring-offset | var(--bg-primary) | inner 2px of Ring/*; must match the canvas, not literal white |
--ring-brand | rgba(10,10,10,0.12) | outer 4px of the exported Ring/brand effect |
--ring-error | rgba(255,0,0,0.12) | outer 4px of the exported Ring/error effect |
--motion-state | 160ms | no motion tokens in the export; §12 baseline |
--motion-ease | cubic-bezier(.2,0,0,1) | no motion tokens in the export; §12 baseline |
--line-height-paragraph-md | 1.5 | line heights live in the text styles, not the variables |
--line-height-paragraph-sm | 1.4286 | line heights live in the text styles, not the variables |
--line-height-caption-md | 1.5 | line heights live in the text styles, not the variables |
Spacing, radius and widths
2. Spacing & Size 50 · 3. Radius 11 · 4. Widths 12. Components bind to the component theme token, never to a raw radius.
Spacing & size 50
| Token | Value | Figma name |
|---|---|---|
--spacing-0 | 0px | UI Spacing/spacing-0 |
--spacing-2 | 2px | UI Spacing/spacing-2 |
--spacing-4 | 4px | UI Spacing/spacing-4 |
--spacing-6 | 6px | UI Spacing/spacing-6 |
--spacing-8 | 8px | UI Spacing/spacing-8 |
--spacing-12 | 12px | UI Spacing/spacing-12 |
--spacing-16 | 16px | UI Spacing/spacing-16 |
--spacing-20 | 20px | UI Spacing/spacing-20 |
--spacing-24 | 24px | UI Spacing/spacing-24 |
--spacing-32 | 32px | UI Spacing/spacing-32 |
--spacing-40 | 40px | UI Spacing/spacing-40 |
--spacing-48 | 48px | UI Spacing/spacing-48 |
--spacing-56 | 56px | UI Spacing/spacing-56 |
--spacing-64 | 64px | UI Spacing/spacing-64 |
--spacing-96 | 96px | UI Spacing/spacing-96 |
--spacing-128 | 128px | UI Spacing/spacing-128 |
--spacing-160 | 160px | UI Spacing/spacing-160 |
--spacing-192 | 192px | UI Spacing/spacing-192 |
--spacing-224 | 224px | UI Spacing/spacing-224 |
--spacing-256 | 256px | UI Spacing/spacing-256 |
--spacing-320 | 320px | UI Spacing/spacing-320 |
--spacing-384 | 384px | UI Spacing/spacing-384 |
--spacing-480 | 480px | UI Spacing/spacing-480 |
--spacing-560 | 560px | UI Spacing/spacing-560 |
--spacing-640 | 640px | UI Spacing/spacing-640 |
--spacing-720 | 720px | UI Spacing/spacing-720 |
--spacing-768 | 768px | UI Spacing/spacing-768 |
--spacing-960 | 960px | UI Spacing/spacing-960 |
--spacing-1280 | 1280px | UI Spacing/spacing-1280 |
--spacing-1440 | 1440px | UI Spacing/spacing-1440 |
--spacing-1920 | 1920px | UI Spacing/spacing-1920 |
--screen-size | 1440px | Screen Size/Size |
--padding-padding | 24px | Padding/padding |
--spacing-1024 | 1024px | UI Spacing/spacing-1024 |
--spacing-80 | 80px | UI Spacing/spacing-80 |
--spacing-1080 | 1080px | UI Spacing/spacing-1080 |
--gap-gap | 24px | Gap/gap |
--spacing-72 | 72px | UI Spacing/spacing-72 |
--font-size-display | 72px | Font Size/display |
--font-size-header-h1 | 60px | Font Size/header-h1 |
--font-size-header-h2 | 48px | Font Size/header-h2 |
--font-size-header-h3 | 36px | Font Size/header-h3 |
--font-size-header-h4 | 30px | Font Size/header-h4 |
--font-size-header-h5 | 24px | Font Size/header-h5 |
--font-size-header-h6 | 20px | Font Size/header-h6 |
--font-size-paragraph-lg | 18px | Font Size/paragraph-lg |
--font-size-paragraph-md | 16px | Font Size/paragraph-md |
--font-size-paragraph-sm | 14px | Font Size/paragraph-sm |
--font-size-caption-md | 12px | Font Size/caption-md |
--font-size-caption-sm | 10px | Font Size/caption-sm |
Radius 11
| Token | Value | Figma name |
|---|---|---|
--radius-none | 0px | radius-none |
--radius-xxs | 2px | radius-xxs |
--radius-xs | 4px | radius-xs |
--radius-sm | 6px | radius-sm |
--radius-md | 8px | radius-md |
--radius-lg | 12px | radius-lg |
--radius-xl | 16px | radius-xl |
--radius-2xl | 20px | radius-2xl |
--radius-3xl | 24px | radius-3xl |
--radius-4xl | 32px | radius-4xl |
--radius-full | 100000px | radius-full |
Widths 12
| Token | Value | Figma name |
|---|---|---|
--width-xxs | 320px | width-xxs |
--width-xs | 384px | width-xs |
--width-sm | 480px | width-sm |
--width-md | 560px | width-md |
--width-lg | 640px | width-lg |
--width-xl | 768px | width-xl |
--width-2xl | 1024px | width-2xl |
--width-3xl | 1080px | width-3xl |
--width-4xl | 1280px | width-4xl |
--width-5xl | 1440px | width-5xl |
--width-6xl | 1920px | width-6xl |
--width-xxxs | 256px | width-xxxs |
Typography
5. Typography 8 tokens. The export stores weights as words and carries no line heights — both are mapped in tokens.css and listed as added roles above.
| Token | Value | Figma name |
|---|---|---|
--family-display | Inter | Family/display |
--weight-regular | regular | Weight/regular |
--family-heading | Inter | Family/heading |
--family-text | Inter | Family/text |
--family-caption | Inter | Family/caption |
--weight-bold | bold | Weight/bold |
--weight-medium | medium | Weight/medium |
--weight-semibold | semibold | Weight/semibold |
Size ramp
| Token | Size | Sample |
|---|---|---|
--font-size-display | 72px | Ag |
--font-size-header-h1 | 60px | Ag |
--font-size-header-h2 | 48px | Ag |
--font-size-header-h3 | 36px | Ag |
--font-size-header-h4 | 30px | Ag |
--font-size-header-h5 | 24px | Ag |
--font-size-header-h6 | 20px | Ag |
--font-size-paragraph-lg | 18px | Ag |
--font-size-paragraph-md | 16px | Ag |
--font-size-paragraph-sm | 14px | Ag |
--font-size-caption-md | 12px | Ag |
--font-size-caption-sm | 10px | Ag |
Component radius themes
6. Themes 8 tokens × 4 modes. Switching the control above swaps the whole set at once.
| Component theme | Full | Normal | Sharp | Slightly Rounded |
|---|---|---|---|---|
--button | 100000px | 8px | 0px | 12px |
--modal | 32px | 16px | 0px | 20px |
--modal-inner-container | 20px | 12px | 0px | 16px |
--input | 8px | 8px | 0px | 12px |
--calendar-header | 100000px | 12px | 0px | 16px |
--pagination | 100000px | 10px | 0px | 14px |
--card | 12px | 8px | 0px | 12px |
--nav-item | 12px | 8px | 0px | 8px |
Dark mode
Dark Mode is a mode in the export, so it is emitted verbatim — 126 tokens that differ from Light. No corrections are applied and no values are invented. Switch it in the top bar.
These are known to read poorly. They are reported, not patched — patching would mean changing the tokens.
| Role | Value | Consequence |
|---|---|---|
| `border-primary` = `border-secondary` | both `#262626` | a container edge and a control edge become indistinguishable |
| `text-tertiary` = `text-quarternary` | both `#a3a3a3` | the four-step text ramp collapses to three |
| `icon-tertiary` = `icon-quarternary` = `icon-disabled` | all `#737373` | a disabled icon reads the same as an enabled one |
| `bg-brand-primary` = `bg-secondary` | both `#171717` | a selected nav item disappears against the control surface |
| `bg-brand-primary_hover` = `bg-brand-primary_press` | both `#262626` | pressed is identical to hover |
| `text-placeholder` | `#737373` | measures 3.78:1 on the dark surface — below the 4.5:1 AA minimum |
| Soft status fills | `bg-error` / `bg-warning` / `bg-success` / `bg-info` | exported as translucent overlays, so their contrast changes with whatever sits behind them |
| Added roles | `--focus-ring`, `--ring-*`, `--shadow-*`, `--border-control` | these are not in the export and carry Light Mode values only; they do not adapt |
| Alpha ramp | `alpha-*-accent-*` | resolves to opaque `#ffffff` in Dark — the alpha is lost, so anything using it as a translucent band renders as a solid white fill |
| `bg-dark` | `#171717` | stays dark in Dark Mode, so a surface meant to invert against the canvas disappears — use `bg-alt`, which flips |
| `bg-error-secondary` | `#dc2626` | a *solid* red in Dark, not a soft tint — any component using it as a soft fill puts `text-error` red-on-red; the Button corrects its own content, other components may not |
| Light Mode corrections | `text-error`, `text-warning`, `text-success`, `text-placeholder`, `text-quarternary` | the contrast fixes applied to Light are not applied here, by request |
Input field
2 sizes × 13 types × 5 states — 130 variants. Radius binds to --input = 8px in the Full theme, not the button pill. Every field is Label / Field / Hint in a 4px column.
States — md
Sizes
All 13 types
Focus and error both add a ring: 0 0 0 2px canvas offset, then 0 0 0 4px tint. The error ring is exported as literal rgba(255,0,0,.12) — pure red, not bg-error-solid.
Input properties
The component set exposes 19 properties. Three are variant axes; the rest are booleans, instance swaps and text slots that toggle optional parts of the anatomy. Optional parts are authored in the markup and hidden by default, so opting in is a class — nothing re-renders.
Playground
All 19 properties
| Property | Kind | Values | Default | Maps to |
|---|---|---|---|---|
Size | variant | md, lg | md | .dos-field--lg |
Type | variant | 13 values | Simple | per-type markup |
State | variant | Placeholder, Focus, Filled, Error, Disabled | Placeholder | .is-* on the wrapper |
has Label? | boolean | True / False | True | .dos-field--no-label to hide |
is Optional | boolean | True / False | False | .dos-field--optional |
is Required | boolean | True / False | False | .dos-field--required |
Leading Icon | boolean | True / False | False | .dos-field--lead-icon |
← Icon | swap | any icon | .dos-input__icon--lead glyph | |
Trailing Icon | boolean | True / False | False | .dos-field--trail-icon |
Icon → | swap | any icon | alert-circle | .dos-input__icon--trail glyph |
🌍 Country | swap | any flag | ghana | flag in .dos-input__addon |
Country Code | boolean | True / False | True | .dos-field--no-country-code to hide |
Password Icon | swap | any icon | lock | leading glyph on Password |
View Icon | swap | any icon | eye | trailing glyph on Password |
Text | text | free text | https:// | .dos-input__addon content |
Payment Icons | swap | card brand | mastercard | trailing brand mark |
Hint | boolean | True / False | False | .dos-field--hint |
Hint Text | text | free text | Hint text goes here | .dos-field__hint content |
Dropdown Icon | swap | any icon | chevron-down | trailing glyph on select-like types |
Hiding the label does not remove it. .dos-field--no-label paired with .sr-only keeps the label in the accessibility tree — a placeholder is not a label, and a field with neither is unusable on a screen reader.
Text area
One size, 5 states. min-height: 72px, content top-aligned. Its resting border is border-secondary, not the border-primary the input field uses — that inconsistency is in the source.
OTP input
6 layouts × 3 states — 18 variants. Cells are 48px squares. Connected shares one outer border; Split is two connected groups with a rule between; Split-Rounded keeps every cell individually rounded.
Layouts
States
Checkbox & radio
Checkbox 12 variants (2 types × 2 states × checked × disabled), radio 8. Both are a 16px control; only the silhouette and the marker differ. Figma calls the indeterminate state Immediate.
Checkbox
Default · uncheckedDefault · checkedImmediateDisabled · uncheckedDisabled · checkedRadio
Both are real <input> elements wrapped in a <label>, so the text is a click target and the control keyboard-toggles without any script.
Toggle
12 variants — 2 types × checked × 2 sizes × disabled. Every dimension derives from the track height: width 1.8×, knob 0.8×, inset 0.1×, which is exactly how the two source sizes relate.
md · offmd · onmd · disabledsm · offsm · onsm · disabledWith text
Button group
2 published variants — Size=sm (32px) and Size=md (44px). The group carries its own border, pill radius and overflow clip; each child also carries a full border, and the clip trims the outer edges.
Children are a distinct _Button Group Unpublished component, not the Button component — hence border-primary and bg-primary rather than the Outline treatment, and md at 44px rather than the Button’s 40px.
Because the group clips, the focus band is drawn inside the child; an outer band would be trimmed.
Pagination & loader
Pagination 4 types. All four share one filled track and a 40px page cell; only the prev/next treatment changes. The active page is a white cell with a border, not an inverted chip, and the page cells sit flush — the group has no gap.
Loader
16px24px · default32pxBadges & chips
2 sizes × 6 types × 3 styles × 6 colors — 216 variants. Radius binds to --button, so chips stay pills alongside the buttons. This is the one component that already ships Color=Info.
Colors × styles, plus every type
| Color | Light | Outline | Solid | Leading Icon | Text with Close Button | Avatar | Country | Icon Only |
|---|---|---|---|---|---|---|---|---|
| Default | Badge | Badge | Badge | Badge | Badge | Badge | 🇬🇭Badge | |
| Brand | Badge | Badge | Badge | Badge | Badge | Badge | 🇬🇭Badge | |
| Success | Badge | Badge | Badge | Badge | Badge | Badge | 🇬🇭Badge | |
| Warning | Badge | Badge | Badge | Badge | Badge | Badge | 🇬🇭Badge | |
| Error | Badge | Badge | Badge | Badge | Badge | Badge | 🇬🇭Badge | |
| Info | Badge | Badge | Badge | Badge | Badge | Badge | 🇬🇭Badge |
Types across all three styles
Sizes
sm · 24pxmd · 28pxAlerts & snackbar
3 colors × 2 sizes × 5 states, plus 5 snackbars — 35 variants. Large stacks the message over its actions with a dismiss button pinned top-right; Small is a single 48px row.
Color = Default
Color = Light
Color = Solid
Snackbar
A snackbar keeps only the status icon — the surface is always bg-dark, so a toast reads the same wherever it appears. It hugs its content rather than taking a fixed width.
Tooltip
18 variants — 2 supporting-text × 9 arrow positions, at With Style=False. The bubble is bg-alt on --radius-lg; the tail is a 12px square rotated 45° that the bubble paints over, leaving a clean triangle.
With supporting text — 280px
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Insert Tooltip
Insert tooltip description here. It would look much better as three lines of text.
Title only — hugs
Insert Tooltip
Insert Tooltip
Insert Tooltip
Insert Tooltip
Insert Tooltip
Insert Tooltip
Insert Tooltip
Insert Tooltip
Insert Tooltip
The shadow is a filter: drop-shadow, not box-shadow — it has to follow the tail's silhouette rather than the bubble's rectangle.
Arrow Position=None drops the tail. In the source that position exists only at With Style=False, which is why the full set is 34 rather than 36.
Avatar
18 variants — 6 sizes × 3 content treatments. Size is the exact Figma value and drives the square dimension; Icon Only, Image / Memoji and Text Only are mutually exclusive.
| Treatment | 20px | 24px | 32px | 40px | 48px | 64px |
|---|---|---|---|---|---|---|
| Icon Only | ||||||
| Image / Memoji | ||||||
| Text Only | DO | DO | DO | DO | DO | DO |
Group
Calender
3 variants. Source spelling preserved — the Figma component is Calender. Header, calendar and footer stack vertically; the header is a pill-shaped selector on bg-secondary, day cells are 40px pills on --button, and the footer carries Cancel / Apply.
Content divider
5 types. The rule is drawn with pseudo-elements, so a divider with centre content needs no extra markup.