DOL Figma Variable Selection - Decision Tree
Given a design task (“I want to X”), pick the right DS-Token variable in ≤3 decisions.
🛑 Match-and-refuse (entry-level): nếu bạn sắp invent tên variable chưa có trong registry, hoặc sắp bind
text-color/*cho icon node, STOP - grepvariable-registry.mdtrước + consultnaming-convention.md§1 (4-category rule). Hex fallback chỉ khi genuinely không có token.
Flow:
- Identify category (4-category rule): is it a fill / text / icon / border?
- Identify family (semantic role): neutral / brand / info / success / warning / danger / special / ai
- Identify level (intensity): dim (subtle bg) / soft (hover) / primary (default) / secondary (focus/subordinate) / subtle (de-emphasized text)
Then look up in variable-registry.md for the exact name + hex.
§1 Category decision - the 4-category rule
Section titled “§1 Category decision - the 4-category rule”First question always: what am I styling?
| Visual property | Category | Figma target |
|---|---|---|
| Background of a frame/shape/component | fill/* or surface-page/* | Frame fill |
| Text inside a text node | text-color/* | Text node fill |
| Icon vector (SVG path fills) | icon-color/* | Vector fill (NOT text-color even if same hex) |
| Stroke on frame / border line / divider / focus ring | border-color/* | Stroke |
Critical: don’t use
text-color/*on icons - even if hex identical today, future mode variants may diverge. See anti-patternfigma-naming-6-binding#02.
§2 Family decision - the 8 semantic roles
Section titled “§2 Family decision - the 8 semantic roles”Second question: what does this element mean?
| Family | Meaning | Typical use |
|---|---|---|
neutral | No semantic meaning; structure/copy | Body text, card borders, page bg, default dividers |
brand | DOL identity; CTA emphasis | Primary button, logo-adjacent accent, hero CTA (use sparingly) |
info | Informational / in-progress / active | Tooltips, progress bars, active tab, “processing” state |
success | Confirmation / correct / positive | Toast success, correct-answer border, completion badge |
warning | Attention / caution / pre-error | Time-running-low indicator, warning banner, expiring status |
danger | Error / destructive / negative | Error message, form-validation fail, destructive action button |
special | Premium / featured / highlighted | Upgrade CTA, special-offer card (rare - reserve for true differentiation) |
ai | AI-generated / AI-initiated content | Narration indicator, AI chat message bg, AI-explanation card |
Color mapping (per ../ds-guideline/DIRECTION.md §4 + color.md):
| Family | Anchor hex (GM mode) | Underlying palette |
|---|---|---|
| brand | #D42525 | red/primary |
| info / progress | #2B52D4 | blue |
| success | #329546 | green |
| warning | #E0A011 | amber/yellow |
| danger | #E24B19 | orange (NOT red - red is brand!) |
| special | #5B37D2 | purple/violet |
| ai | #006B99 | cyan |
| neutral | #2B3138 / #6C7885 / #E2E5E9 | slate |
DOL divergence from typical convention:
danger ≠ redin DOL because red = brand. Most UIs use red for error; DOL uses orange. This is intentional.
§3 Level decision - the 6 intensity modifiers
Section titled “§3 Level decision - the 6 intensity modifiers”Third question: how strong should the treatment be?
| Level | Use for | Visual character |
|---|---|---|
dim | Subtle tint backgrounds, de-emphasized state | Lightest shade (200-300 range) |
soft | Hover states, gentle emphasis | Mid-light (400 range) |
primary | Default active state, main emphasis | Canonical shade (600) |
secondary | Subordinate to primary, focus rings, secondary text | Near-primary (700 range) |
subtle | Very muted body / caption / placeholder | Mid-dark (700-800 for text) |
stress | Maximum emphasis (rare) | Darkest shade (900+ for text) |
disabled | Inactive / non-interactive | Low-contrast grayed variant |
highlight | Focus indicator, selection emphasis | Distinct + saturated |
deep | Strong divider / dark border | Higher-contrast border variant |
inverse | Text on dark/vivid background | White / near-white |
Not all families have all levels - refer to variable-registry.md for exact availability per family.
§4 Common design task → variable lookup
Section titled “§4 Common design task → variable lookup”Direct recipes for frequently-built components. Each recipe names the Figma variable you bind.
§4.1 Text (body, headings, captions)
Section titled “§4.1 Text (body, headings, captions)”| Task | Category | Family | Level | Variable name |
|---|---|---|---|---|
| Body text on page | text-color | neutral | primary | --text-color-neutral-primary |
| Muted caption / supporting text | text-color | neutral | dim | --text-color-neutral-dim |
| Placeholder text in input | text-color | neutral | disabled | --text-color-neutral-disabled |
| Heading emphasis (strongest) | text-color | neutral | stress | --text-color-neutral-stress |
| Brand emphasis (CTA label in colored button) | text-color | on-inverse | primary | --text-color-on-inverse-primary |
| Link default | text-color | info | primary | --text-color-info-primary |
| Error message inline | text-color | danger | primary | --text-color-danger-primary |
| Success confirmation inline | text-color | success | primary | --text-color-success-primary |
§4.2 Button
Section titled “§4.2 Button”| Task | Fill | Text | Border | Notes |
|---|---|---|---|---|
| Primary CTA | --fill-brand-primary (#D42525) | --text-color-on-inverse-primary (white) | none or matching fill | DOL brand color |
| Primary info action (learn more, OK) | --fill-info-primary | --text-color-on-inverse-primary | none | Blue #2B52D4 |
| Success confirm | --fill-success-primary | --text-color-on-inverse-primary | none | Green #329546 |
| Danger destructive | --fill-danger-primary | --text-color-on-inverse-primary | none | Orange - NOT red |
| Secondary (outlined) | transparent / surface-page-primary | --text-color-neutral-primary | --border-color-neutral-primary | Stroke carries emphasis |
| Ghost (subtle) | transparent | --text-color-neutral-secondary | none | Hover adds fill-neutral-dim |
| Disabled | --fill-neutral-dim | --text-color-neutral-disabled | none | Low contrast |
§4.3 Input field
Section titled “§4.3 Input field”| State | Fill | Border | Text | Icon |
|---|---|---|---|---|
| Default | --input-color-bg-color-default | --border-color-neutral-primary | --text-color-neutral-primary | --icon-color-neutral-subtle |
| Focus | --input-color-bg-color-default | --border-color-progress-secondary (focus-ring global) | --text-color-neutral-primary | --icon-color-neutral-primary |
| Error | --input-color-bg-color-default | --border-color-danger-primary | --text-color-neutral-primary | --icon-color-danger-primary |
| Disabled | --input-color-bg-color-disable | --border-color-neutral-subtle | --text-color-neutral-disabled | --icon-color-neutral-disabled |
| Readonly | transparent | transparent | --text-color-neutral-primary | - |
Focus ring rule: ALL components share ONE focus border token - --border-color-progress-secondary. Never per-component colors (anti-pattern figma-naming-6-binding#04).
§4.4 Alert / status banner
Section titled “§4.4 Alert / status banner”| Severity | Fill (bg) | Border | Icon | Text |
|---|---|---|---|---|
| Info | --fill-info-dim | --border-color-info-secondary | --icon-color-info-primary | --text-color-info-primary |
| Success | --fill-success-dim | --border-color-success-secondary | --icon-color-success-primary | --text-color-success-primary |
| Warning | --fill-warning-dim | --border-color-warning-secondary | --icon-color-warning-primary | --text-color-warning-primary |
| Danger / Error | --fill-danger-dim | --border-color-danger-secondary | --icon-color-danger-primary | --text-color-danger-primary |
Pattern: always fill-{family}-dim + border-{family}-secondary + icon-{family}-primary + text-{family}-primary. Four variables per alert.
§4.5 Card / surface container
Section titled “§4.5 Card / surface container”| Task | Fill | Border | Shadow |
|---|---|---|---|
| Default card on white page | --surface-page-neutral-primary (white) | --border-color-neutral-primary | --shadow-neutral-to-bot-2 |
| Elevated (e.g., modal, dropdown) | --surface-page-neutral-primary | --border-color-neutral-subtle | --shadow-neutral-to-bot-3 |
| Interactive hover | --surface-page-neutral-primary | --border-color-neutral-deep | --shadow-neutral-to-bot-3 |
| Tinted section bg (subtle) | --surface-page-neutral-dim | none | none |
White-on-white rule: white card on white page MUST have border (--border-color-neutral-primary or subtle). Shadow alone doesn’t suffice. See direction-10-color-brand#09.
§4.6 Badge / status pill
Section titled “§4.6 Badge / status pill”| Status | Fill | Text |
|---|---|---|
| Info / neutral | --fill-info-dim | --text-color-info-primary |
| Active / “in progress” | --fill-progress-dim (same as info) | --text-color-progress-primary |
| Success / complete | --fill-success-dim | --text-color-success-primary |
| Warning / pending | --fill-warning-dim | --text-color-warning-primary |
| Error / failed | --fill-danger-dim | --text-color-danger-primary |
| Neutral / default | --fill-neutral-dim | --text-color-neutral-primary |
§4.7 Icon colors (standalone / inline)
Section titled “§4.7 Icon colors (standalone / inline)”| Task | Variable |
|---|---|
| Default inline icon | --icon-color-neutral-subtle |
| Active / selected icon | --icon-color-neutral-primary |
| Decorative muted icon | --icon-color-neutral-dim |
| Icon inside colored button (white-on-brand) | inherit text color (--text-color-on-inverse-primary) via Figma inheritance, OR bind icon-color directly if Figma can’t inherit |
| Error icon | --icon-color-danger-primary |
| Success checkmark | --icon-color-success-primary |
| AI identity (narration, chat, etc.) | --icon-color-ai-primary (cyan) |
§4.8 AI-initiated surfaces (narration, chat, inline AI)
Section titled “§4.8 AI-initiated surfaces (narration, chat, inline AI)”| Element | Variable |
|---|---|
| AI message bubble bg | --fill-ai-dim |
| AI message text | --text-color-ai-primary |
| AI identity icon | --icon-color-ai-primary |
| AI indicator border | --border-color-ai-secondary |
| AI-specific shadow | --shadow-ai-to-bot-3 (soft cyan tint - reserved for AI context) |
Why AI has its own semantic family: signals “this content is AI-generated” without confusing with brand/info. Cyan (
#006B99) is DOL’s AI color per practice.md §5 Skill Color Usage.
§4.9 Divider / separator line
Section titled “§4.9 Divider / separator line”| Purpose | Variable |
|---|---|
| Between list items | --border-color-neutral-subtle |
| Between form sections | --border-color-neutral-primary |
| Heavy divider (section break) | --border-color-neutral-deep |
| Colored section divider (rare) | Match section family: --border-color-{family}-secondary |
§4.10 Feature-specific (dashboard, progress, leaderboard)
Section titled “§4.10 Feature-specific (dashboard, progress, leaderboard)”Feature tokens live in --stat-*, --program-skill-*, --leaderboard-*, --table-color-* namespaces. See variable-registry.md §1.6 and §1.7 for full enumeration.
§5 Typography selection
Section titled “§5 Typography selection”§5.1 Font family
Section titled “§5.1 Font family”| Task | Variable | Font |
|---|---|---|
| Body text | --font-family-body | Inter |
| Heading | --font-family-heading | Plus Jakarta Sans |
| KID domain (all text) | --font-family-kid-* | Quicksand |
| Monospace / code | (none - use Figma default or add to DS if needed) | - |
§5.2 Font size - role-prefixed
Section titled “§5.2 Font size - role-prefixed”DOL font-size tokens are role-prefixed, not raw scale. Pick the role first, then the size.
| Role | Sizes available | Use for |
|---|---|---|
--font-size-display-* | 2xl/4xl/5xl/6xl/7xl/8xl/9xl (24-64px) | Hero display numbers, marketing headline |
--font-size-heading-* | base/md/lg/xl/2xl/3xl/4xl/5xl/6xl/7xl (14-56px) | Page / section / card headings |
--font-size-body-* | xs/sm/base/md/lg/xl/2xl (10-24px) | Paragraphs, card body, form copy |
--font-size-label-* | xs/sm/base (10-14px) | Tiny labels, captions, tags |
--font-size-quote-* | lg/xl/2xl (18-24px) | Pull quotes, testimonial copy |
Common picks:
- Body default =
--font-size-body-base(14px) - minimum for body per DIRECTION §6 - Card title =
--font-size-heading-md(16px) or-lg(18px) - Section heading =
--font-size-heading-2xl(24px) or-3xl(28px) - Hero display =
--font-size-display-5xl(40px) or larger - Caption =
--font-size-label-xs(10px) - use sparingly
§5.3 Line height - variant-scoped
Section titled “§5.3 Line height - variant-scoped”Line height tokens follow pattern --line-height-<role>-<size>-<variant> where variant = compact | standard | extended.
| Reading context | Variant | Example |
|---|---|---|
| Headings, labels | compact | --line-height-heading-2xl-compact |
| Body paragraph default | standard | --line-height-body-base-standard |
| Long-form reading (article, explanation) | extended | --line-height-body-base-extended |
For raw numeric leading (rare), use --leading-scale-{4..72} (in 4px increments).
§5.4 Font weight
Section titled “§5.4 Font weight”| Use | Variable | Value |
|---|---|---|
| Light (rare, display only) | --font-weight-light | 300 |
| Body default | --font-weight-regular | 400 |
| Medium emphasis | --font-weight-medium | 500 |
| Button labels, strong emphasis | --font-weight-bold | 700 |
| NEVER on buttons | --font-weight-black | 900 - anti landing-1.7-hero#05 |
Canonical button weight = --font-weight-bold (700). Don’t mix bold + black in same component hierarchy.
§6 Spacing selection
Section titled “§6 Spacing selection”| Scope | Variable prefix |
|---|---|
| Inside a component (padding, internal gap) | --inset-* or --spacing-* |
| Between UI elements in same block | --spacing-xs/sm/md/lg/xl |
| Between page sections | --section-gap-* (32-80px range) |
| Page outer margin (responsive) | --page-margin-* |
| Max container width | --max-width-* (per responsive viewport) |
Rhythm rule (anti-pattern direction-10-spacing-depth#02): vary gap values across atomic levels. Atom gap-2, molecule gap-3, organism gap-4, section gap-8+. Using gap-4 everywhere = slop-04 monotonous-spacing.
§7 Radius selection
Section titled “§7 Radius selection”DOL radius scale is numeric (--radius-0 through --radius-50, plus half-steps -0-5, -1-5, -2-5, -3-5) with resolved values in 4px increments. Pick component-scoped variant when available.
| Element type | Variable | Approx value |
|---|---|---|
| Sharp corners | --radius-0 | 0 |
| Tiny (tag, chip, subtle) | --radius-1 | 4px |
| Small (icon button) | --radius-2 | 8px |
| Default baseline (most inputs) | --radius-3 | 12px |
| Medium (card, alert) | --radius-4 | 16px |
| Large (modal, panel) | --radius-5 | 20px |
| Extra large (hero card) | --radius-6 / --radius-7 | 24-28px |
| Pill (full rounded) | --radius-max or --pill-shape | 999 |
| Component-specific preferred | --button-radius-* / --input-radius-* / --modal-radius-* / --alert-radius-* / --dropdown-radius-* / --tooltip-radius-* / --uploader-radius-* | - |
Preference order:
- Component-scoped (
--button-radius-md) - bound to specific component type - Control sizing (
--control-md) - if component doesn’t have its own - Raw radius (
--radius-3) - last resort for atypical elements
Why component-scoped beats raw: if DS adjusts “buttons should be slightly rounder”, one change to
--button-radius-*updates all buttons; raw--radius-3would affect every element using that value indiscriminately.
§8 Shadow selection
Section titled “§8 Shadow selection”| Purpose | Variable |
|---|---|
| Card elevation (default, downward) | --shadow-neutral-to-bot-{1..5} (1 = soft, 5 = heavy) |
| Modal / overlay | --shadow-neutral-to-bot-4 or -5 |
| Floating toolbar (upward shadow) | --shadow-neutral-to-top-{1..5} |
| Horizontal elevation | --shadow-neutral-to-left-{2,3} or -to-right-{2,3} |
| AI-specific soft glow | --shadow-ai-to-bot-{3..5} |
| Brand campaign element (rare) | --shadow-brand-to-bot-{3..5} |
| Paper / card-stock aesthetic | --shadow-paper-to-bot-{3..5} |
NEVER use
--shadow-{family}-*for decorative glow on neutral components. Colored shadow = DIRECTION §10 slop-07 (dark-glow). Reserved for campaign / special state only.
§9 Mode awareness
Section titled “§9 Mode awareness”§9.1 GM (General) mode - DEFAULT
Section titled “§9.1 GM (General) mode - DEFAULT”Every token selection above targets GM mode. 95% of Figma work.
§9.2 KM (KID) mode
Section titled “§9.2 KM (KID) mode”Switch to KM when working on DOL Kid domain surfaces. Variable names identical - Figma mode switch resolves to KM values internally.
When to switch: user explicitly mentions KID / DOL Kid context, OR file is within KID-scoped design file.
Rule: don’t mix GM + KM tokens in same component (anti-pattern figma-naming-6-binding#06 - covered by Q-gate F6).
§9.3 Dark mode
Section titled “§9.3 Dark mode”Most tokens have darkValue defined - Figma mode auto-resolves. Check variable-registry.md Dark column; if blank, token uses same value across modes.
Rule: don’t hand-bind dark-specific hex; use the semantic token and let mode-swap handle.
§10 Decision shortcuts
Section titled “§10 Decision shortcuts”“I don’t know which family to use” → usually neutral. Semantic families require explicit semantic meaning. Default to neutral when in doubt.
“I don’t know which level” → usually primary. Levels refine when you need subtle/emphasized variants.
“The exact variable doesn’t seem to exist”:
- Search
variable-registry.mdwith grep - try alternate family names - Check if component layer has a composed token (e.g.,
--button-radius-lgvs raw--control-lg) - If still missing, flag to DS-Token team. DON’T invent (anti-pattern
figma-naming-6-binding#05) - Last resort: documented hex fallback - mark as workaround in component description
“Two tokens look interchangeable” → prefer the more specific one:
- Component-scoped > semantic-scoped > base-raw
button-radius-md>radius-md>control-md
Related
Section titled “Related”naming-convention.md- 4-category rule + intensity modifiers + WHYvariable-registry.md- all 838 AI-facing tokens categorized with hex values../anti-pattern-registry.md-figma-naming-6-bindingscope (binding anti-patterns)../ds-guideline/color.md- color philosophy + shade scale math../ds-guideline/typography.md- typography deep reference../ai-entry/FIGMA-AI.md§5.1 - F1-F7 quantified gates