Design tokens: de ontbrekende schakel tussen design en code

Als ik terugkijk op de websites en applicaties die ik de afgelopen jaren heb ontwikkeld, zie ik telkens hetzelfde patroon terugkomen. Een nieuw project begint vaak met een fris ontwerp en een schone codebase. Ik zet een aantal CSS-variabelen op voor kleuren, typografie en spacing, zodat alles netjes en consistent blijft.

In het begin werkt dat prima.

Naarmate het project groeit, groeit echter ook het aantal uitzonderingen. Een knop blijkt net een andere kleur nodig te hebben. Een specifieke pagina vraagt om afwijkende spacing. Na iedere design review komen er nieuwe variabelen bij om aan de laatste wensen te voldoen. Op een gegeven moment werd het steeds lastiger om te bepalen welke variabele waarvoor bedoeld was. En als ik geen goede plek meer kon vinden binnen het bestaande systeem, eindigde ik soms met een hardcoded waarde.

Het resultaat was vaak hetzelfde: een verzameling variabelen zonder duidelijke structuur, aangevuld met uitzonderingen die het onderhoud ingewikkelder maken.

Waarom CSS-variabelen alleen niet genoeg zijn

CSS-variabelen zijn een geweldige manier om hergebruik te stimuleren. Maar op zichzelf vertellen ze niets over hun functie binnen een ontwerp. Neem bijvoorbeeld:

```css
--color-blue-500: #0077B6;
```

Wanneer je deze variabele tegenkomt in een component weet je één ding zeker: de kleur is blauw. Maar waarom is deze kleur gebruikt? Is dit de primaire merkkleur? Is het een linkkleur? Is het bedoeld voor call-to-action knoppen? Mag deze kleur aangepast worden wanneer de huisstijl verandert? De variabele bevat een waarde, maar geen betekenis. En die betekenis vormt vaak de kloof tussen design en development.

Een designer denkt namelijk in termen van:

  • Primaire actie
  • Vlakkleur
  • Tekstkleur
  • Successtatus

Terwijl een developer vaak werkt met:

  • Hex-codes
  • Pixelwaardes
  • CSS-variabelen

Beide spreken eigenlijk een andere taal.

Design tokens als gedeelde taal

Design tokens vormen een vertaallaag tussen design en development. Een design token is een benoemde ontwerpbeslissing. Het kan een kleur, lettergrootte, spacing-waarde of een andere ontwerpkeuze vertegenwoordigen.

Bijvoorbeeld:

```css
action-primary-background
button-large-font-size
text-body-default
```

Het grote voordeel is dat zowel designers als developers dezelfde termen gebruiken. In plaats van te praten over: “Die blauwe kleur moet iets donkerder.” Praat je over: “action-primary-background moet aangepast worden.” Dat lijkt misschien een klein verschil, maar het zorgt ervoor dat ontwerpbeslissingen een vaste plek krijgen binnen het systeem.

Een token-systeem opbouwen

Om design tokens schaalbaar te houden, worden ze meestal georganiseerd in verschillende lagen. Elke laag heeft een eigen verantwoordelijkheid.

1. Primitives

Primitives vormen de basis van het systeem. Dit zijn de enige tokens die daadwerkelijke waardes bevatten, zoals kleuren, afstanden en lettergroottes.

Voor kleuren kan dat er bijvoorbeeld zo uitzien:

  • color-blue-100: #E6F4FA
  • color-blue-200: #BFE3F2
  • color-blue-900: #003247

Voor typografie:

  • font-size-100: 12px
  • font-size-200: 14px
  • font-size-900: 48px

Primitives bevatten geen betekenis. Ze zijn simpelweg de bouwstenen van het systeem.

2. Semantische tokens

Daarom introduceren we een tweede laag: semantische tokens. Deze laag koppelt een betekenis aan een primitive.

```css
--action-primary-background: var(--color-blue-500);
--action-primary-text: var(--color-white);
--text-body-default: var(--color-gray-900);
--surface-background-brand: var(--color-blue-100);

Nu wordt het systeem veel begrijpelijker.

Een component hoeft niet meer te weten welke kleur blauw gebruikt moet worden. Het hoeft alleen te weten dat het de primaire actieachtergrond nodig heeft. Hierdoor ontstaat een duidelijke scheiding tussen ontwerpbeslissingen en implementatie. Een wijziging aan de huisstijl hoeft niet langer in componenten doorgevoerd te worden, maar kan centraal worden beheerd via het token-systeem.

3. Component tokens

In grotere systemen kan zelfs een semantische laag nog te generiek zijn. Daarom voegen veel design systemen nog een derde laag toe: component tokens.

```css
.button-cta {
    --button-cta-bg: var(--action-primary-background);
    --button-cta-text: var(--action-primary-text);

    background: var(--button-cta-bg);
    color: var(--button-cta-text);
}
```

Hiermee ontstaat een duidelijke hiërarchie: **Primitive → Semantisch → Component**

Modes: light mode, dark mode en theming

Een van de grootste voordelen van deze structuur wordt zichtbaar zodra je meerdere thema’s wilt ondersteunen. Met design tokens wordt dark mode een mapping-probleem in plaats van een component-probleem.

```css
:root {
    --surface-page: var(--color-gray-0);
    --text-body-default: var(--color-gray-900);
    --action-primary-background: var(--color-blue-500);
}

[data-theme="dark"] {
    --surface-page: var(--color-gray-900);
    --text-body-default: var(--color-gray-0);
    --action-primary-background: var(--color-blue-300);
}
```

De componenten veranderen niet. Dat maakt deze aanpak niet alleen geschikt voor dark mode, maar ook voor meerdere merken, white-label oplossingen, campagnepagina’s en klantspecifieke thema’s.

Waarom dit een game changer is

Sinds ik design tokens op deze manier inzet, zie ik drie grote voordelen.

  1. Designers en developers hebben de mogelijkheid om in dezelfde taal te spreken: designbeslissingen krijgen een vaste naam en betekenis.
  2. Theming wordt aanzienlijk eenvoudiger: dark mode, white-labeling en branding worden configuratieproblemen in plaats van ontwikkelprojecten.
  3. Onderhoud wordt voorspelbaar: aanpassingen vinden plaats op de juiste laag binnen het systeem.

Praktijkvoorbeeld

De voordelen van design tokens worden pas echt zichtbaar wanneer je ze toepast in een concreet product. Binnen onze DNS management software ctrlDNS gebruiken we deze principes dagelijks om white-label thema’s schaalbaar en beheersbaar te houden.

Waar deze theorie echt tot leven komt, is in de theme editor van ctrlDNS. Met deze zelfontwikkelde editor beheren en configureren wij de white-label thema’s van het platform.

De editor stelt ons in staat om snel de primaire kleuren van een nieuw thema vast te leggen. Deze vormen de basis van het ontwerp en worden opgeslagen als primitives binnen ons token-systeem. Vervolgens kunnen we met behulp van component tokens de verschillende onderdelen van de interface verfijnen en afstemmen op de gewenste uitstraling.

Om het configureren zo gebruiksvriendelijk mogelijk te maken, hebben we een systeem ontwikkeld waarbij modifiers gecombineerd kunnen worden met de primaire CSS-variabelen. Zo kunnen we bijvoorbeeld eenvoudig een hover-kleur genereren op basis van de primaire kleur: `$color-primary, +10%`

Hierbij wordt automatisch de primaire kleur gebruikt en 10% lichter gemaakt. Hierdoor hoeven niet alle kleurvarianten handmatig gedefinieerd te worden en blijft het thema eenvoudig te onderhouden.

Deze aanpak biedt verschillende voordelen. Nieuwe white-label thema’s kunnen in korte tijd worden opgezet zonder dat er maatwerk in de code nodig is. Door het gebruik van design tokens blijft de uitstraling van de applicatie bovendien consistent, ongeacht hoeveel verschillende thema’s worden ondersteund. Daarnaast wordt het onderhoud aanzienlijk eenvoudiger, omdat wijzigingen centraal kunnen worden doorgevoerd zonder dat componenten afzonderlijk aangepast hoeven te worden.

Het resultaat is een flexibel en schaalbaar systeem waarin de theorie achter design tokens direct wordt toegepast in de praktijk. Nieuwe klanten kunnen sneller worden voorzien van een eigen huisstijl, ontwikkeltijd wordt beperkt en de applicatie blijft ook op de lange termijn beheersbaar en eenvoudig uit te breiden.

De grootste kracht

Wat voorheen een verzameling losse CSS-variabelen was, is uitgegroeid tot een systeem waarin designers en developers dezelfde taal spreken. En daarin zit voor mij de grootste kracht van design tokens.

Bas Everaarts
Technologie