Blog

Design System: op maat of kant-en-klaar?

Een design system is een investering. Afhankelijk van je behoeften en budget kun je kiezen voor een volledig op maat gemaakt design system, of voor een kant-en-klare oplossing die je alleen hoeft aan te passen naar eigen wens. Er zijn talloze UI-componentenbibliotheken beschikbaar van de plank. Hoe beslis je welke je gebruikt voor jouw design system?

Natuurlijk is er meer aan een design system dan alleen de UI-componenten, zoals adoptie, werkwijze en governance. Hier schrijven we ook graag over. In dit artikel focus ik me op de technische aspecten van het ontwikkelen van design system-componenten en hoe een kant-en-klare bibliotheek daarbij kan helpen.

Voordelen kant-en-klare componentenbibliotheken

Waarom zou je een kant-en-klare UI-componentenbibliotheek gebruiken? Enkele, misschien voor de hand liggende, voordelen:

  • Klaar voor gebruik. Andere ontwerpers en ontwikkelaars hebben er honderden, misschien zelfs duizenden uren werk in de componenten gestoken. Je kunt ze vaak gratis gebruiken, wat je veel tijd en geld bespaart.
  • Uitgebreid getest. Deze componenten zijn vaak al uitgebreid getest en hebben goede testdekking, wat gebruikers van je design system behoedt voor kinderziektes en de adoptie vergemakkelijkt.
  • Goed gedocumenteerd. Dit verhoogt de bruikbaarheid van je design system.
  • Grote community. Er zijn veel andere gebruikers die tutorials hebben geschreven, vragen hebben beantwoord, problemen hebben gemeld en opgelost.
  • Onderhouden door anderen. Zodat je dit zelf niet hoeft te doen.

Nadelen kant-en-klare componentenbibliotheken

    • Ontwerp past mogelijk niet. Het voorgeprogrammeerde uiterlijk van een kant-en-klare componentenbibliotheek is de grootste beperking. Dit kun je omzeilen door ongestijlde componenten te gebruiken. Daarover later meer.
    • Geen controle over de richting van de componentenbibliotheek. Hoewel het nu aan je eisen voldoet, kan dat in de toekomst veranderen.
    • Ontbrekende of andere ontwerpprincipes. De benadering van de bibliotheek komt niet altijd overeen met de werkwijze van je team.
    • Naamgeving en API's komen mogelijk niet overeen met je eigen design system. Omdat je geen controle hebt over de bibliotheek van de leverancier, moet je mogelijk je naamgeving en API's aanpassen. Of je kunt abstracties om de componenten van de bibliotheek heen bouwen.
    • Gebouwd voor scenario's die je niet nodig hebt. Dit kan onnodige rompslomp creëren.
    • Onzekerheid over onderhoud. De mensen of organisatie achter de bibliotheek kunnen hun prioriteiten veranderen of de bibliotheek volledig laten vallen. Natuurlijk kun je altijd de bibliotheek forken of als vendor-code gebruiken als de licentie dit toestaat (kijk bijvoorbeeld naar shadcn/ui die deze strategie van nature volgt).
    • Beperkende licentie. Dit kan je limiteren in hoe je de bibliotheek (commercieel) kunt gebruiken, nu en in de toekomst. Het is dus verstandig om dit vooraf goed te bestuderen.
    MUI Material UI gestylede componenten
    MUI Material UI gestijlde componenten

    Gestijlde vs ongestijlde (ook wel Headless) componenten

    Wanneer je aan componentenbibliotheken denkt, denk je misschien aan Google's Material UI in een specifieke framework-variant, zoals Angular of React. Dit zijn voorbeelden van gestijlde componentenbibliotheken die CSS bevatten, met misschien enkele themamogelijkheden, en direct klaar zijn voor gebruik. Een nieuwe categorie bibliotheken wint aan populariteit: ongestijlde, ook wel headless, componenten. Deze componenten bieden functionaliteit, zoals een tab-interface of een autocomplete-invoer, maar leveren of passen geen styling toe. Ongestijlde componenten geven je meer flexibiliteit, en daarmee meer verantwoordelijkheid.

    We gebruiken meestal ongestijlde componentenbibliotheken voor snel prototypen en projecten met minimale ontwerpvereisten. Bijvoorbeeld in een kleine business-to-business applicatie. In de meeste gevallen ontwikkelen we volledig aangepaste design systems of gebruiken we (gedeeltelijk) een ongestijlde componentenbibliotheek.

    Kant-en-klare componentenbibliotheken

    Wanneer je besluit een bestaande UI-componentenbibliotheek te gebruiken, hoe bepaal je dan welke je moet kiezen? Wij geloven dat een goede eerste stap is om 2 of 3 kandidaten voor te selecteren op basis van ‘gestijld’ of ‘ongestijld’ en het framework dat je gebruikt voor ontwikkeling. Er zijn behoorlijk wat opties om uit te kiezen. Hieronder een inventarisatie van populaire componentenbibliotheken die kant-en-klaar beschikbaar zijn:

    Library

    Styled

    Unstyled

    React

    Vue

    Svelte

    Lit

    Stencil

    Vanilla WC

    MUI

    Unstyled / base *nieuw

    Vuetify

    PrimeVue

    mode

    Headless UI

    * onofficieel

    * onofficieel

    Radix

    port

    Lion

    Tanstack

    Kuma UI

    Downshift

    Adobe Spectrum

    React ARIA

    React Spectrum

    Drab

    FAST

    Reach UI

    Andere factoren om te overwegen

    Naast framework en stylingstrategie in de matrix, zijn er andere dingen die je mogelijk wilt overwegen, zoals wie zit er achter het framework, wat is hun filosofie, hoe ziet hun roadmap eruit en wat zijn de plannen voor onderhoud en ondersteuning.

    'Unstylen' van gestijlde componenten

    Wat als je een gestijlde componentenbibliotheek leuk vindt, maar deze verder wilt aanpassen dan de mogelijkheden toestaan? Wat je kunt doen, is de componenten "unstylen" door hun CSS niet te gebruiken en in plaats daarvan je eigen CSS te schrijven. Omdat de CSS-selectoren niet de officiële (en waarschijnlijk niet-gedocumenteerde) API van de bibliotheek zijn, kan dit riskant zijn, omdat nieuwere versies je implementatie stuk kunnen maken. Als je besluit deze route te volgen, is het waarschijnlijk verstandig om de bibliotheek als vendor-code te gebruiken in plaats van als pakket.

    Headless UI Vue onstylede componenten
    Headless UI Vue ongestijlde componenten

    Selectie van de kant-en-klare opties verfijnen

    Wanneer je meerdere kandidaten voor UI-componentenbibliotheken hebt, kun je een meer gedetailleerde vergelijking maken. Een vergelijking op basis van functies en componenten helpt om te bepalen hoe geschikt een kandidaat werkelijk is en hoeveel je zelf nog moet doen, evenals hoeveel budget dat zou kosten.

    Als we bijvoorbeeld besluiten dat een ongestijlde React-bibliotheek is wat we nodig hebben, blijven we met meerdere kandidaten zitten, zoals Headless UI, Radix, Tanstack, Downshift en mogelijk anderen. Hier is een matrix die ze vergelijkt, en aangeeft of ze aan onze eisen voldoen (✅) of hoeveel inspanning of budget (💶 - 💶💶💶💶) het zou kosten om een specifieke functie te bieden:

    Headless UI v1

    Headless UI v2

    Radix

    Tanstack

    Downshift

    Autocomplete

    💶

    💶💶

    Button

    💶

    💶

    💶

    Dialog

    💶💶

    💶💶

    Disclosure

    💶

    💶

    Dropdown

    💶💶

    💶💶

    Form

    💶💶💶💶

    💶💶💶💶

    Table

    💶💶

    💶💶

    💶💶

    💶💶

    Zoals je ziet, bieden sommige bibliotheken veel componenten, terwijl andere slechts een kleine set specifieke componenten bieden. Headless UI v2 is onlangs uitgebracht en bevat nu nog meer componenten. Als je deze componenten ook nodig hebt, vermindert de nieuwe versie je inspanning nog verder.

    Het maken van een vergelijking van componentenbibliotheken zou ons moeten helpen om te bepalen welke het beste bij onze behoeften past. Misschien besluiten we om componenten uit verschillende bibliotheken te mixen. Dat is typisch alleen een optie voor ongestijlde componenten, omdat we ze allemaal kunnen thematiseren zodat ze een consistent uiterlijk krijgen.

    Tot nu toe is dit allemaal theorie. Als laatste stap in de selectie maken we graag een proof-of-concept voor een realistische situatie om te verifiëren of de geselecteerde kandidaat aan onze behoeften voldoet.

    Hulp nodig bij het kiezen van de juiste technologie voor jouw framework?

    Stel ons je vragen en wij kijken hoe we jou het best kunnen helpen.

    Voorbeeld: Vuetify bij Deltares

    Onze klant Deltares is een geavanceerd wateronderzoeksinstituut. Ze ontwikkelen projecten met grote datasets en water simulatiemodellen. Deze projecten vereisen vaak een gebruikersinterface om met deze datasets en modellen te communiceren. Aangezien de apps voornamelijk voor intern gebruik en B2B-toepassingen zijn, is er beperkte behoefte aan maatwerk. Bovendien, door de vaak beperkte budgetten voor elke app, hebben ze meer aan een gestandaardiseerde oplossing. Dit maakt deze apps een goede case voor een kant-en-klaar design system. Deltares heeft een Vue-ecosysteem, dus we hebben gekozen voor Vuetify, de meest volwassen en complete gestijlde Vue-bibliotheek.

    Drie tools van Deltares met gedeelde functionaliteiten

    Om een Deltares-thema in de Vue-apps te gebruiken, hebben we een @deltares/design-tokens en een @deltares/vuetify-theme pakket ontwikkeld. Het gebruik van de (lichte en donkere) thema's is eenvoudig door te geven aan Vuetify:

    import Vue from 'vue';
    import Vuetify from 'vuetify/lib';
    import themes from '@deltares/vuetify-theme';
    
    Vue.use(Vuetify);
    
    export default new Vuetify({
      theme: { themes },
    });
    

    Hoe deze themes eruitzien:

    import tokens from '@deltares/design-tokens';
    
    const { light, dark } = tokens
    
    export default {
      light: {
        primary: light.blue100,
        secondary: light.orange,
        accent: dark.blue60,
        error: light.error,
        info: light.informative,
        success: light.success,
        warning: light.warning,
      },
      dark: { /* ... */ }
    }
    

    Vuetify bood een solide basis met veelvoorkomende componenten zoals formulierelementen en dialoogvensters. Hierdoor konden wij ons richten op het uitbreiden van deze set met Deltares-specifieke componenten, zoals een geo-viewer lay-out, grafieken en kaartcomponenten in een @deltares/vue-components pakket. Wil je meer zien? Alle Deltares Vue-pakketten beschikbaar als open source.

    Radix UI onstylede componenten
    Radix UI ongestijlde componenten

    Voorbeeld: Radix, Downshift en Dayzed bij PostNL

    PostNL is een onderneming met tientallen digitale producten, zowel B2C als B2B. In tegenstelling tot Deltares, wil PostNL een volledige controle over het uiterlijk en de werking van hun producten. Ze stellen hoge eisen aan de kwaliteit en toegankelijkheid van hun gebruikersinterfacecomponenten. Het technologie-landschap van PostNL is divers, met een belangrijke rol voor React-webapplicaties. Om aan hun behoeften te voldoen, hebben we ervoor gekozen om volledig op maat gemaakte componenten te combineren met kant-en-klare ongestijlde React-componenten. Het voordeel van deze ongestijlde componentbibliotheken is dat je ze gemakkelijk combineert en aanpast. PostNL profiteert van algemene componenten zoals tabs van Radix, in combinatie met specifieke functionele componenten zoals de autocomplete van Downshift en de datepicker van Dayzed.

    Radix tabcomponenten in Stamp

    Dit is hoe de Radix-tabcomponenten worden gebruikt binnen het Stamp Design System van PostNL:

    import {
      TabsList as RadixTabsList,
      TabsListProps as RadixTabsListProps,
    } from '@radix-ui/react-tabs';
    
    export type TabListProps = RadixTabsListProps;
    
    export const TabList = forwardRef<HTMLDivElement, TabListProps>(
      ({ className, children, ...props }, ref) => {
        return (
          <RadixTabsList 
            className={ clsx('stamp-tab-list', className) }
            ref={ ref }
            { ...props }
          >
            { children }
          </RadixTabsList>
    )});
    

    Deze TabList is slechts een minimale wrapper rondom de Radix-component. De Tab component is verder uitgebreid met PostNL-specifieke iconen en indicatoren:

    import {
      TabsTrigger,
      TabsTriggerProps as RadixTabsTriggerProps
    } from '@radix-ui/react-tabs';
    
    export interface TabProps extends RadixTabsTriggerProps {
      icon?: ReactNode;
      indicatorValue?: string;
    }
    
    export const Tab = forwardRef<HTMLButtonElement, TabProps>(
      ({ className, value, icon, indicatorValue, ...props }, ref) => (
        <TabsTrigger
          className={ clsx(className, 'stamp-tab') }
          ref={ ref }
          { ...props }
          value={ value }
        >
          { icon && <span className={'stamp-tab__icon'}>{ icon }</span> }
          <span className={'stamp-tab__content'}>{ props.children }</span>
          {indicatorValue && <span className={'stamp-tab__indicator'}>{ indicatorValue }</span>}
        </TabsTrigger>
    ));
    

    Het voordeel van het gebruik van deze ongestijlde UI-componenten dat ze ons volledige controle geven. Het nadeel van het gebruik van kant-en-klare componenten in vergelijking met de door ons op maat gemaakte componenten, is dat de derde-partij componenten hun eigen API hebben. In het geval van PostNL was React niet het enige framework dat we moesten ondersteunen. De manier waarop de Dayzed datepicker de props en stijlen verwachtte, maakte het moeilijker om een goede abstractie tussen de frameworks te delen.

    Desondanks heeft het ons veel tijd bespaard door niet vanaf nul een eigen datepicker te ontwikkelen. Bij andere, eenvoudigere componenten waren deze voordelen niet altijd opgewassen tegen de toegevoegde complexiteit. Daarom hebben we ervoor gekozen om deze componenten vanaf het begin zelf te ontwikkelen. Je kunt ze allemaal vinden in de interactieve documentatie van het Stamp Design System. Kun je zien welke componenten uit een bibliotheek komen en welke op maat zijn gemaakt?

    Tot slot

    Ik hoop dat dit artikel je helpt bij het kiezen van de juiste aanpak en het selecteren van de beste (on)gestijlde componentbibliotheek voor jouw systeem. Als je er al een hebt gemaakt, ben ik benieuwd naar jouw ervaringen en welke strategie je gebruikt. Heb je andere kandidaten die we aan onze matrix zouden moeten toevoegen?

    Gerelateerde blog posts

    ← Alle blogposts

    Hulp nodig met jouw design system?

    Ontdek wat wij voor je kunnen doen voor jouw digitale product.

    Lees meer over onze service