ADR-020 ActifActive contract

4px grid as the systemic dimensional scale

DateDate
2026-05-29
DécideursDecision makers
Guilherme Negreiros — Design System Lead

Context

The project had used 4 primitive spacing values from the outset (8, 16, 20, 32 px) — all multiples of 4 — without this decision being formally documented or the full scale defined. This ADR formalizes the implicit decision and completes the scale.

Situation before

"space": {
  "2": "8px",
  "4": "16px",
  "5": "20px",
  "8": "32px"
}

Only four values, named by their multiplier without the base module (4px) being explicitly declared. Any new spacing value required an ad hoc decision with no normative reference.


Decision

Base module: 4px

Every dimensional value in the system is a multiple of 4px. This module is the smallest allowed increment.

1 unit = 4px

Full spacing primitive scale

TokenValueMultiplierTypical usage
primitive.space.14px4 × 1Micro — separator, minimal internal gap
primitive.space.28px4 × 2Small — vertical control padding
primitive.space.312px4 × 3Intermediate
primitive.space.416px4 × 4Standard — horizontal control padding
primitive.space.520px4 × 5Medium
primitive.space.624px4 × 6Large intermediate
primitive.space.832px4 × 8Large — separation between components
primitive.space.1040px4 × 10Very large
primitive.space.1248px4 × 12Macro
primitive.space.1664px4 × 16Macro — separation between page sections

The 4 existing values (2, 4, 5, 8) remain unchanged — full backward compatibility.

Extension rule

If a new spacing value is required, it must be a multiple of 4. If the value doesn't exist in the primitive scale, create the missing token rather than use an arbitrary value.


Rationale

Why 4px?

Industry convergence: Material Design (Google), Polaris (Shopify), Atlassian Design System, Carbon (IBM), Spectrum (Adobe) — all use a 4px or 8px grid (8px being simply a subset of 4px at double spacing).

Natural alignment: High-density screens (2×, 3×) divide whole pixels into sub-pixels. A 4px grid guarantees that every value stays a whole number at every display density.

Decision consistency: With a 4px grid, designers and agents don't have to arbitrate between close values (14px vs 16px). The grid decides: it's 12px or 16px, not 14px.

Automated audit: audit-tokens.js can detect any spacing value that isn't a multiple of 4 and flag it as drift.


Rejected alternatives

AlternativeReason for rejection
8px gridToo coarse for micro-spacing (a badge's internal gap, a tag's padding). 4px offers more flexibility without chaos.
Fibonacci scale (4, 8, 12, 20, 32...)Memorization complexity with no demonstrable visual benefit for this project.
T-shirt scale (xs/sm/md/lg/xl)Opaque to agents — space.4 (16px, 4×4) is more traceable than space.md (an arbitrary value).
Keep the 4 existing valuesInsufficient: teams create ad hoc values outside the grid as soon as a step is missing.

Consequences

For tokens:

  • primitive.space goes from 4 to 10 values
  • All existing semantic references remain valid (no path changes)
  • 6 new primitives available for future semantic tokens

For AI agents:

  • Any spacing request can be resolved by referencing the scale
  • Drift (hardcoded px, off-grid values) is detectable by audit

For teams:

  • Memorable rule: "if it's not in the table, it's not in the system"
  • Spacing decisions are reduced to picking a step, not a value

Debt cleared:

  • The implicit decision to use a 4px grid is now formalized and traceable

Contexte

Le projet utilisait depuis l'origine 4 valeurs d'espacement primitives (8, 16, 20, 32 px) — toutes des multiples de 4 — sans que cette décision soit formellement documentée ni l'échelle complète définie. Cette ADR formalise la décision implicite et complète l'échelle.

Situation avant

"space": {
  "2": "8px",
  "4": "16px",
  "5": "20px",
  "8": "32px"
}

Quatre valeurs seulement, nommées par leur multiplicateur sans que le module de base (4px) soit explicitement déclaré. Toute nouvelle valeur d'espacement nécessitait une décision ad hoc sans référence normative.


Décision

Module de base : 4px

Toute valeur dimensionnelle du système est un multiple de 4px. Ce module est le plus petit incrément autorisé.

1 unité = 4px

Échelle complète des primitives d'espacement

TokenValeurMultiplicateurUsage type
primitive.space.14px4 × 1Micro — séparateur, gap interne minimal
primitive.space.28px4 × 2Petit — padding contrôle vertical
primitive.space.312px4 × 3Intermédiaire
primitive.space.416px4 × 4Standard — padding contrôle horizontal
primitive.space.520px4 × 5Moyen
primitive.space.624px4 × 6Intermédiaire large
primitive.space.832px4 × 8Grand — séparation entre composants
primitive.space.1040px4 × 10Très grand
primitive.space.1248px4 × 12Macro
primitive.space.1664px4 × 16Macro — séparation entre sections de page

Les 4 valeurs existantes (2, 4, 5, 8) restent inchangées — rétrocompatibilité totale.

Règle d'extension

Si une nouvelle valeur d'espacement est requise, elle doit être un multiple de 4. Si la valeur n'existe pas dans l'échelle primitive, créer le token manquant plutôt qu'utiliser une valeur arbitraire.


Argumentaire

Pourquoi 4px ?

Convergence sectorielle : Material Design (Google), Polaris (Shopify), Atlassian Design System, Carbon (IBM), Spectrum (Adobe) — tous utilisent une grille 4px ou 8px (8px étant simplement un sous-ensemble de 4px à double espacement).

Alignement naturel : Les écrans à haute densité (2×, 3×) divisent les pixels entiers en sous-pixels. Une grille de 4px garantit que toutes les valeurs restent des entiers à toutes les densités d'affichage.

Cohérence décisionnelle : Avec une grille de 4px, les designers et agents n'ont pas à arbitrer entre des valeurs proches (14px vs 16px). La grille tranche : c'est 12px ou 16px, pas 14px.

Audit automatisé : L'audit-tokens.js peut détecter toute valeur d'espacement qui n'est pas un multiple de 4 et la signaler comme dérive.


Alternatives rejetées

AlternativeRaison du rejet
Grille 8pxTrop granulaire pour les micro-espacements (gap interne d'un badge, padding de tag). 4px offre plus de flexibilité sans chaos.
Échelle de Fibonacci (4, 8, 12, 20, 32...)Complexité mémorielle sans bénéfice visuel démontrable pour ce projet.
Scale T-shirt (xs/sm/md/lg/xl)Opaque pour les agents — space.4 (16px, 4×4) est plus traçable que space.md (valeur arbitraire).
Garder les 4 valeurs existantesInsuffisant : les équipes créent des valeurs ad hoc hors grille dès qu'un échelon manque.

Conséquences

Pour les tokens :

  • primitive.space passe de 4 à 10 valeurs
  • Toutes les références sémantiques existantes restent valides (aucun chemin ne change)
  • 6 nouveaux primitifs disponibles pour les futurs tokens sémantiques

Pour les agents IA :

  • Toute demande d'espacement peut être résolue par référence à l'échelle
  • Les dérives (px en dur, valeurs hors-grille) sont détectables par audit

Pour les équipes :

  • Règle mémorisable : « si ça n'est pas dans la table, ce n'est pas dans le système »
  • Les décisions d'espacement se réduisent à choisir un échelon, pas une valeur

Dette soldée :

  • La décision implicite d'utiliser une grille 4px est maintenant formalisée et traçable
← ADR-019 ADR-021 →