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:

  1. Keep cDLSystem values invariant.
  2. Add an independent PDS Density Semantics variable collection with standard and compact modes for the first pilot.
  3. Bind governed component metrics to those semantic density variables.
  4. Keep explicit component size properties (xs–2xl) as a separate axis.
  5. Allow component-specific density controls only for approved high-density patterns such as data tables and lists.
  6. 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, and language token 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 density modes 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 dense prop, 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:

CollectionModesTokensObserved role
cDLModeslight, dark122 per modeSemantic foreground, background, border, state, overlay, and interaction colors
cDLPrimitivesmode1261Literal brand, palette, role, and alpha colors
cDLSystemmode1199Numeric/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:

FamilyCountRange/examples
Spacing350–384, including 1px and half-step values
Dimensions200–240 with named xs–14xl steps
Font size2310–128
Type line-height2012–120
Generic leading812–40
Icon512, 16, 24, 32, 48
Radius100–32 plus full
Border50, 1, 2, 4, 8
Motion duration120–1000ms
Breakpoint/container20responsive/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:

  • standard
  • compact

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 contract

The 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.

  • size answers: which semantic component scale is this instance?
  • density answers: how does that semantic size resolve in this context?
  • appearance, treatment, status, and state retain 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:

CollectionExample selection
PDS semantic colorlight or dark
PDS density semanticsstandard 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 = rest

They 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

CategoryFirst-pilot treatmentReason
Control/row heightChangePrimary density lever with strong public precedent
Block/inline paddingChangeControls visual rhythm without redefining foundations
Gaps and surface insetsChange selectivelyImportant to composition; should be semantic, not global scale replacement
Typography sizeHold constantSAP/Material evidence shows density can work without smaller text; PDS lacks semantic type roles in this export
Typography line heightHold constant initiallyChanging it affects readability and vertical clipping; assess after role audit
Icon sizeHold constant initiallyOften belongs to component size, not density
Border widthHold constantSpectrum explicitly keeps it stable; little evidence for density coupling
RadiusHold constantPrimarily shape/brand, not information density
Breakpoints/gridKeep separateResponsive layout and density solve different problems
Hit targetSeparate from visual heightPointer/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 apply

This 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 standard to current PDS behavior wherever possible.
  • Derive compact mappings only from measured component needs and existing cDLSystem values.
  • 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 size props 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 size properties.
  • 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?”:

  1. Which component metrics are governed by inherited density semantics?
  2. Which components retain explicit local sizes or are density-stable?
  3. Does compact ever alter a semantic typography role, or only geometry?
  4. What are the minimum visual and interactive targets by pointer modality?
  5. Which containers are allowed to override page density?
  6. 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 compact as equivalent to component small.
  • 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