PDS density architecture proposal
Status: architecture proposal based on the 2026-07-31 token snapshot and the public-system density research. This document does not set final density values or modify PDS tokens.
Executive conclusion
PDS already has the beginnings of the right separation for density:
- invariant color and numeric foundations
- semantic light/dark color modes
- a governed component-size vocabulary
What it does not yet have is a semantic dimensional layer between raw numeric foundations and components. Adding compact values directly to the spacing scale would make primitives context-dependent; adding compact to the color-mode collection would couple independent axes; implementing every difference as a component variant would duplicate decisions and prevent a coherent product default.
The proposed direction is therefore a hybrid:
- Keep
cDLSystemvalues invariant. - Add an independent PDS Density Semantics variable collection with
standardandcompactmodes for the first pilot. - Bind governed component metrics to those semantic density variables.
- Keep explicit component
sizeproperties (xs–2xl) as a separate axis. - Allow component-specific density controls only for approved high-density patterns such as data tables and lists.
- Keep color, typography strategy, responsive behavior, and input modality separate from density unless evidence establishes a specific coupling.
This supports:
same component + same meaning + same size property + different inherited density context
without creating separate commerce and enterprise component libraries.
Practitioner evidence added 2026-08-13
Three additional implementation accounts reinforce the hybrid direction while sharpening its risks:
- SAS documents independent
core,theme,density, andlanguagetoken dimensions. Its locale/type conflict is a concrete reason to audit typography independently instead of shrinking the whole interface by one multiplier. - Uber demonstrates screen-density switching with a component-specific Figma collection. The visible
listitem densitymodes remap parent padding and minimum height while deliberately leaving child padding invariant. This supports inherited modes but does not, by itself, validate one global density collection. Public summaries disagree on the exact tag count, and the Tag example concerns variable-driven component reduction more broadly rather than density alone. - Meridian provides inspectable code for ancestor-scoped density variables combined with explicit Button/Input sizes, an additional Table
denseprop, and a density-stable Card size contract. Its implementation is informative, but the new repository is not evidence of mature adoption.
This does not change the proposed architecture. It increases the importance of locale testing, explicit mixing policy, Figma discoverability/documentation, and measuring library complexity before and after the pilot. See _practitioner-evidence.md.
1. What is in the snapshot
PDS_figma_tokens.json contains three top-level collections:
| Collection | Modes | Tokens | Observed role |
|---|---|---|---|
cDLModes | light, dark | 122 per mode | Semantic foreground, background, border, state, overlay, and interaction colors |
cDLPrimitives | mode1 | 261 | Literal brand, palette, role, and alpha colors |
cDLSystem | mode1 | 199 | Numeric/string foundations for dimensions, spacing, type, icons, borders, radii, motion, opacity, blur, breakpoints, and containers |
Of the 122 cDLModes variables, 100 differ between light and dark and 22 remain the same. All 122 resolved colors in both modes match a literal in cDLPrimitives.
The principal cDLSystem families are:
| Family | Count | Range/examples |
|---|---|---|
| Spacing | 35 | 0–384, including 1px and half-step values |
| Dimensions | 20 | 0–240 with named xs–14xl steps |
| Font size | 23 | 10–128 |
| Type line-height | 20 | 12–120 |
| Generic leading | 8 | 12–40 |
| Icon | 5 | 12, 16, 24, 32, 48 |
| Radius | 10 | 0–32 plus full |
| Border | 5 | 0, 1, 2, 4, 8 |
| Motion duration | 12 | 0–1000ms |
| Breakpoint/container | 20 | responsive/layout foundations |
The controlled vocabulary already reserves density with extraCompact, compact, standard, and spacious, but the token JSON contains no density variables or density modes. Vocabulary Ruleset v4
2. How the current tokens appear to work
The intended color path is recognizable:
cDLPrimitives literal color → cDLModes semantic color → component binding
For example, fgDefault resolves differently in light and dark while retaining the same semantic name.
The numeric path currently appears flatter:
cDLSystem numeric foundation → direct component/layout use
There are no exported semantic variables such as control height, field padding, data-row height, or surface inset. There are also no exported component metric tokens for Button, Input, Select, Table, List, Card, Navigation, or Dialog.
This means the existing foundations provide values but not a governed explanation of which values should change together when density changes.
3. Snapshot limitations that must be resolved first
The file is a JSON-encoded string containing a second JSON object. More importantly, it contains only resolved scalar values. It does not retain:
- Figma variable IDs or collection IDs
- alias references
- resolved variable types and scopes
- descriptions
- code syntax
- remote/local status
- node/component bindings
Every semantic color matches a primitive value, but 109 of 122 semantic tokens have more than one primitive with that same literal value. For example, #bb0628 could correspond to roleDanger70, palleteRed70, or roleValue70. The intended alias cannot be recovered safely from equality alone.
Before restructuring, the native Figma alias and binding graph needs to be exported through the Variables API or a DTCG export that preserves alias metadata. Figma variables support aliases, collection-specific modes, inherited node modes, scopes, and code syntax. Figma variables overview Figma Variables API
The snapshot also contains established naming defects such as pallete… and borderDefaultInverseDefaultOnEmpahsis. Those should be catalogued as migration issues, not silently corrected as part of density work.
4. Why the existing collections should not carry density directly
Do not put density modes in cDLModes
cDLModes is a semantic color collection. Adding standard and compact there would make color and geometry alternatives in one mode axis, or require combined modes such as light-standard, light-compact, dark-standard, and dark-compact.
Separate collections can resolve independent modes on the same node and inherit those selections through descendants. That is the appropriate mechanism for independent color and density axes. Figma resolved variable modes
Do not make cDLSystem primitives mode-dependent
Tokens such as spacing4 = 16, dimensions5xl = 40, and iconMd = 24 should remain stable facts. If spacing4 changed meaning under compact mode, every consumer—layout, component padding, decorative spacing, and potentially hit-area geometry—would change whether or not it was intended to participate in density.
Density should select among primitives; it should not redefine them.
Do not solve everything through duplicated component variants
Pure component variants would allow compact buttons and fields, but every product and component would repeat the density decision. It would be harder to set a coherent product default, audit completeness, or change a shared density contract.
Explicit variants remain useful for component size and approved exceptions, but not as the only system-level mechanism.
5. Proposed token architecture
flowchart LR S["cDLSystem<br/>Invariant foundations"] --> D["PDS Density Semantics<br/>standard | compact"] P["cDLPrimitives<br/>Color foundations"] --> C["cDLModes<br/>light | dark"] D --> CT["Component metric contracts"] C --> CT CT --> B["Same governed component<br/>Button, Field, Table, List…"] SZ["Explicit size property<br/>xs–2xl"] --> CT I["Input modality / accessibility"] --> B
Layer 1: invariant foundations
Retain cDLSystem as the source of raw numeric values. Density-semantic values should alias these foundations rather than introduce arbitrary one-off numbers wherever possible.
Layer 2: independent density semantics
Create a numeric variable collection provisionally named PDS Density Semantics.
Initial modes:
standardcompact
The existing vocabulary reserves spacious and extraCompact, but they should not be populated until a validated use case and component coverage exist. A vocabulary option is not evidence that four operational modes are needed.
Candidate semantic groups—not final names—should cover intent rather than raw scale position:
- control minimum height
- control block and inline padding
- control internal gap
- field minimum height and content padding
- data row/header height
- data cell block and inline padding
- list-item minimum height and gap
- surface/card inset
- section/stack gap
- navigation item height and inset
- overlay/dialog inset where the component is approved to participate
Each mode value aliases a stable cDLSystem token. No final mappings are proposed until component measurements and bindings are inventoried.
Layer 3: component metric contracts
Components should not bind indiscriminately to generic spacing primitives. Each governed component needs a small metric contract, for example:
Button / Primary / size=md
height → density semantic: control height md
padding inline → density semantic: control inline padding md
content gap → density semantic: control gap md
label typography → semantic typography role; unchanged by density initially
icon size → component size contract; unchanged by density initially
hit target → interaction-modality/accessibility contractThe component contract may be represented as component variables or directly through component bindings in the first pilot. In code, it should become named component custom properties so exceptions remain explicit.
Layer 4: explicit component size
Keep the controlled size axis (xs, sm, md, lg, xl, 2xl) independent from density.
sizeanswers: which semantic component scale is this instance?densityanswers: how does that semantic size resolve in this context?appearance,treatment,status, andstateretain their existing meanings.
This prevents compact from becoming a synonym for small.
6. Figma activation model
A product or page frame would select modes independently:
| Collection | Example selection |
|---|---|
| PDS semantic color | light or dark |
| PDS density semantics | standard or compact |
Figma resolves a mode for each variable collection and descendants inherit ancestor selections, so both axes can coexist without combined mode names. Figma resolvedVariableModes
Component instances continue to use normal properties such as:
appearance = primary
size = md
state = restThey should not require separate “Enterprise Button” and “Commerce Button” variants. The inherited density collection changes their bound metrics.
Local density overrides should be technically possible but governed. Suggested policy:
- root/page selection establishes the default
- local overrides are allowed only on documented density containers or approved components
- arbitrary alternating density inside a workflow is not supported
- data tables/lists may expose an explicit row-size or compact control independent of page density
- overlays and short task flows may remain standard even inside compact applications
Figma extended collections could later support product-specific overrides, but they are Enterprise-plan functionality and are not required for the base density model. Figma extended collections
7. Code activation model
The closest code equivalent is a scoped provider or attribute that sets semantic CSS variables:
<div data-pds-color="light" data-pds-density="compact">
<pds-button appearance="primary" size="md">Save</pds-button>
</div>Conceptually:
[data-pds-density='standard'] {
--pds-control-height-md: var(--pds-dimension-PLACEHOLDER);
--pds-control-padding-inline-md: var(--pds-spacing-PLACEHOLDER);
}
[data-pds-density='compact'] {
--pds-control-height-md: var(--pds-dimension-PLACEHOLDER);
--pds-control-padding-inline-md: var(--pds-spacing-PLACEHOLDER);
}
.pds-button[data-size='md'] {
min-block-size: var(--pds-control-height-md);
padding-inline: var(--pds-control-padding-inline-md);
}The placeholders are deliberate: the component audit should determine which existing foundation token each mode aliases.
This model allows a global default, nested approved scopes, and one component implementation. Component-specific size props remain available for tables, inputs, buttons, and exceptional contexts.
8. What should and should not change in the first density pilot
| Category | First-pilot treatment | Reason |
|---|---|---|
| Control/row height | Change | Primary density lever with strong public precedent |
| Block/inline padding | Change | Controls visual rhythm without redefining foundations |
| Gaps and surface insets | Change selectively | Important to composition; should be semantic, not global scale replacement |
| Typography size | Hold constant | SAP/Material evidence shows density can work without smaller text; PDS lacks semantic type roles in this export |
| Typography line height | Hold constant initially | Changing it affects readability and vertical clipping; assess after role audit |
| Icon size | Hold constant initially | Often belongs to component size, not density |
| Border width | Hold constant | Spectrum explicitly keeps it stable; little evidence for density coupling |
| Radius | Hold constant | Primarily shape/brand, not information density |
| Breakpoints/grid | Keep separate | Responsive layout and density solve different problems |
| Hit target | Separate from visual height | Pointer/touch accessibility cannot be inferred from visible density |
Typography can be revisited selectively after PDS has semantic roles such as label, body, title, and supporting text. A commerce-oriented content/type strategy may be real, but it should not be smuggled into a generic density mode without evidence.
9. Component participation model
Use three participation classes:
A. Density-responsive foundations
These should resolve through inherited semantic density tokens:
- Button
- Input/Text Field
- Select/Combobox
- common navigation items
- common list items
- basic card/surface padding
B. Density-responsive with explicit local size
These need inherited defaults plus a component control because information structure varies:
- Data Table/Data Grid
- dense lists and trees
- toolbars
- pagination
- complex forms
C. Density-stable or constrained
These should initially retain standard geometry or participate only in documented parts:
- modal/dialog task surfaces
- popovers and date pickers
- touch-primary controls
- destructive confirmation flows
- components whose focus/touch geometry would overlap when compacted
The classification must be validated component by component; it should not be inferred from category names alone.
10. Accessibility contract
Density should distinguish visual size from interactive target size.
- WCAG 2.2 AA requires a 24 × 24 CSS px target or sufficient spacing, subject to exceptions.
- 44 × 44 CSS px is the stronger AAA target criterion and is also a common system-level touch recommendation.
- A compact pointer-oriented control may be visually shorter while retaining hit slop when adjacent targets permit it.
- Coarse-pointer/touch contexts should not automatically inherit a compact visual target without an input-specific rule.
- Keyboard focus, error messaging, 200% text resizing, 400% zoom/reflow, and label readability need validation independently of density.
WCAG 2.5.8 Target Size (Minimum) WCAG 2.5.5 Target Size (Enhanced)
11. Product-context policy
Do not name density modes commerce and enterprise.
Instead, product archetypes choose defaults:
commerce experience → standard density by default
enterprise workspace → compact density by default
touch/coarse input → interaction policy may require standard targets
data-heavy region → approved local row-size override may applyThis keeps density reusable and avoids assuming every commerce page is spacious or every enterprise workflow is compact. Product type becomes policy/configuration, not a second theme or component library.
12. Phased path forward
Phase 0: recover the real token graph
- Export native Figma variables with collection IDs, modes, aliases, types, scopes, descriptions, code syntax, and publish status.
- Inventory bindings from variables to component nodes.
- Treat the current JSON as a resolved reference snapshot, not a migration source.
- Record but do not opportunistically rename existing tokens.
Phase 1: create a component metric inventory
For Button, Text Field, Select, Table, List, Card, Navigation, and Dialog, record:
- current visual height/min-height
- block/inline padding and gaps
- text role and line height
- icon size and slot size
- radius and borders
- interactive target size
- responsive changes
- current Figma variable/style binding
- current code token/prop binding
- locale-specific type or line-height requirements
Classify each metric as invariant, density-responsive, explicit-size-driven, responsive, or input-modality-driven.
Phase 2: define the two-mode semantic contract
- Create the proposed density semantic names.
- Map
standardto current PDS behavior wherever possible. - Derive
compactmappings only from measured component needs and existingcDLSystemvalues. - Document component clamps and exclusions.
- Keep typography and icons unchanged unless a component-specific test establishes a need.
- Prototype the Figma binding graph both ways before committing: component metrics aliased to one shared density-semantic collection, versus component-specific collections like Uber’s visible List Item example. Compare inheritance clarity, number of mode selectors, cross-component synchronization, and author discoverability.
Phase 3: pilot representative components
Pilot one component from each anatomy family:
- Button
- Text Field
- Select/Combobox
- Data Table
- List/Navigation item
- Card
- Dialog as a deliberate constrained/non-participating case
Test the same semantic component and size in both density contexts, rather than duplicating variants by product.
Phase 4: establish Figma/code parity
- Generate or map CSS variables from the same semantic source.
- Add a density provider/attribute in code.
- Keep component
sizeprops aligned with the controlled vocabulary. - Add visual regression matrices for color × density × size × state.
- Publish a Figma usage page showing root mode selection and sanctioned local overrides.
- Document how designers discover the active inherited mode and distinguish it from explicit component
sizeproperties. - Record baseline and post-pilot component/variant counts so library-complexity changes are measured rather than inferred.
Phase 5: validate before expansion
Measure:
- visible rows/actions gained in compact layouts
- task completion and error rates
- target overlap and pointer accuracy
- keyboard and focus behavior
- truncation and localization stress
- 200% text resize and 400% zoom/reflow
- component coverage and unresolved hard-coded dimensions
Only then determine whether spacious or extraCompact is justified.
13. Decisions required after the audit
The next decision set is narrower than “which density system should PDS use?”:
- Which component metrics are governed by inherited density semantics?
- Which components retain explicit local sizes or are density-stable?
- Does compact ever alter a semantic typography role, or only geometry?
- What are the minimum visual and interactive targets by pointer modality?
- Which containers are allowed to override page density?
- Is density user-selectable, product-configured, automatically detected, or some combination?
These decisions can be made from the component inventory without creating a second design system or prematurely defining four density modes.
14. Main risks to avoid
- Revaluing the raw spacing scale by mode.
- Combining light/dark and density into four Cartesian-product modes.
- Treating
compactas equivalent to componentsmall. - Shrinking typography, icons, radius, and hit targets as one multiplier.
- Making commerce/enterprise token names permanent product silos.
- Allowing arbitrary nested density overrides without a participation policy.
- Generating compact values before recovering real aliases and component bindings.
Research basis
- Cross-system comparison
- Density token-model analysis
- Practitioner evidence and source-strength assessment
- Normalized implementation data
- All-system token-library manifest
- Research structure and conventions
- Density decision handoff
- PDS token snapshot
- PDS controlled vocabulary
- Figma variables overview
- Figma VariableCollection API
- Figma variable inheritance