Gepubliceerd op

Wat is shadcn/ui? Doel, voordelen en gebruik in moderne React-apps begrijpen

Auteurs

    Wat is shadcn/ui? Doel, voordelen en gebruik in moderne React-apps begrijpen

    Moderne React-projecten staan vaak voor een lastige afweging: gebruik je een kant-en-klare UI-bibliotheek (snel, maar weinig flexibel) of ontwerp je een eigen systeem (flexibel, maar tijdrovend om te bouwen)?
    Daar komt shadcn/ui van pas: een nieuwe aanpak voor UI-ontwikkeling die je volledige controle over je code geeft en tegelijk de afwerking van een volwassen componentenbibliotheek biedt.

    In deze gids onderzoeken we wat shadcn/ui is, waarom het zo populair is geworden onder React- en Next.js-ontwikkelaars en hoe je het kunt gebruiken om je eigen UI-werk te versnellen zonder flexibiliteit te verliezen.

    Wat is shadcn/ui?

    shadcn/ui (vaak eenvoudigweg shadcn genoemd) is geen traditioneel npm-pakket of componentenbibliotheek met themaondersteuning zoals Material UI of Chakra UI.
    Het is een verzameling hoogwaardige opensource React-componenten, gebouwd met:

    • Tailwind CSS (voor vormgeving)
    • Radix UI (voor toegankelijke basiscomponenten zonder vormgeving)
    • Lucide Icons (voor overzichtelijke, consistente SVG-pictogrammen)

    Maar hier zit het verschil:

    In plaats van het als afhankelijkheid te installeren, kopieer je de daadwerkelijke broncode van elke component naar je eigen project.

    Dat betekent dat elke knop, elk dialoogvenster en elk keuzemenu in je eigen codebase staat, door jou bewerkbaar is, van een thema kan worden voorzien en onder jouw versiebeheer valt.

    Je kunt het zien als een componentgenerator of UI-startpakket, in plaats van een afhankelijkheid.

    Hoe het werkt

    Het shadcn/ui-project biedt een CLI-tool die componenten rechtstreeks in je project genereert:

    npx shadcn-ui@latest add button
    

    Deze opdracht downloadt een kant-en-klare, toegankelijke Button-component en voegt die toe aan je lokale map components/ui/. Vervolgens kun je de component aanpassen, Tailwind-klassen wijzigen, varianten bijstellen of deze afstemmen op je ontwerpsysteem.

    Elke component bestaat gewoon uit React + Tailwind + Radix, zonder verborgen logica of runtimeafhankelijkheid.

    Waarom ontwikkelaars shadcn/ui gebruiken

    1. Volledig eigenaarschap van code

    In tegenstelling tot UI-bibliotheken waarbij je vertrouwt op ondoorzichtige afhankelijkheden, geeft shadcn je de volledige broncode van de component. Je kunt:

    • Stijlen rechtstreeks bewerken
    • Props of varianten toevoegen
    • Eigen logica integreren (zoals analyse of machtigingen)

    Het is jouw UI, met jouw regels, zonder te wachten tot beheerders een PR samenvoegen.

    2. Gebouwd op bewezen fundamenten

    Elke component wordt gebouwd met:

    • Tailwind CSS → vormgeving met utilityklassen
    • Radix UI → toegankelijke basiscomponenten zonder vormgeving
    • Lucide Icons → moderne SVG-pictogrammen
    • clsx / tailwind-variants → overzichtelijk voorwaardelijk beheer van klassen

    Hierdoor zijn je componenten zowel toegankelijk als klaar voor productie en volgen ze standaard de best practices voor ontwerpsystemen.

    3. Consistentie en snelheid

    Je krijgt een samenhangend, mooi uitgangspunt voor je UI:

    • Consistente spatiëring, typografie en een consistent kleurensysteem
    • Donkere modus en thema's via CSS-variabelen
    • Gebruiksklare lay-out- en interactiepatronen (keuzemenu's, modale vensters, tooltips)

    Je kunt interfaces gaan leveren die ontworpen aanvoelen, zonder elke component opnieuw uit te vinden.

    4. Geen afhankelijkheid van een leverancier

    Omdat de componenten gewoon code zijn, kun je:

    • Er een eigen afsplitsing van maken
    • Ze vervangen
    • Ze combineren met andere bibliotheken

    Als shadcn/ui ooit verandert of je behoeften groter worden dan het biedt, blijven je componenten volledig van jou.

    Veelgebruikte componenten en voorbeelden

    Hier zijn enkele van de populairste shadcn/ui-componenten en hoe ze er in gebruik uitzien.

    Voorbeeld 1: knop

    import { Button } from '@/components/ui/button'
    
    export default function Example() {
      return (
        <div className="space-x-2">
          <Button>Default</Button>
          <Button variant="outline">Outline</Button>
          <Button variant="destructive">Delete</Button>
        </div>
      )
    }
    

    Waarom dit goed werkt:

    • Ingebouwde varianten zoals outline, destructive en ghost.
    • Volledige themaondersteuning met de ontwerptokens van Tailwind.
    • Eenvoudig genoeg om aan te passen zonder consistentie te verliezen.

    De knopvarianten begrijpen

    Wanneer je het volgende uitvoert:

    npx shadcn-ui@latest add button
    

    Maakt de CLI een button.tsx-bestand in components/ui/, meestal zoals dit:

    // components/ui/button.tsx
    import * as React from 'react'
    import { cva } from 'class-variance-authority'
    import { cn } from '@/lib/utils'
    
    const buttonVariants = cva(
      'inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:opacity-50 disabled:pointer-events-none',
      {
        variants: {
          variant: {
            default: 'bg-primary text-primary-foreground hover:bg-primary/90',
            outline: 'border border-input bg-background hover:bg-accent hover:text-accent-foreground',
            destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
            ghost: 'hover:bg-accent hover:text-accent-foreground',
            link: 'text-primary underline-offset-4 hover:underline',
          },
          size: {
            default: 'h-10 px-4 py-2',
            sm: 'h-9 rounded-md px-3',
            lg: 'h-11 rounded-md px-8',
            icon: 'h-10 w-10',
          },
        },
        defaultVariants: {
          variant: 'default',
          size: 'default',
        },
      }
    )
    
    export interface ButtonProps
      extends React.ButtonHTMLAttributes<HTMLButtonElement>,
        VariantProps<typeof buttonVariants> {}
    
    function Button({ className, variant, size, ...props }: ButtonProps) {
      return <button className={cn(buttonVariants({ variant, size, className }))} {...props} />
    }
    
    export { Button, buttonVariants }
    

    Wat zijn outline, destructive en ghost dan?

    Het zijn stijlvarianten die vooraf in die buttonVariants-configuratie zijn gedefinieerd. Je hoeft ze niet handmatig te definiëren: ze worden standaard met de gegenereerde component meegeleverd.

    Elke variant komt overeen met een ander patroon van Tailwind-klassen:

    VariantVisuele stijlGebruikelijke toepassing
    defaultEffen primaire knop (bg-primary, witte tekst)Belangrijkste actie (bijvoorbeeld “Opslaan”, “Verzenden”).
    outlineTransparante achtergrond, zichtbare randSecundaire actie of minder nadruk (“Annuleren”).
    destructiveRode/gevaarkleur (bg-destructive)Acties met destructieve gevolgen (“Wissen”, “Verwijderen”).
    ghostMinimale vormgeving, subtiel effect bij aanwijzenKnoppen met weinig nadruk (bijvoorbeeld pictogrammen, secundaire links).
    linkVormgegeven als een tekstlinkVoor navigatie binnen doorlopende tekst.

    Dus wanneer je dit schrijft:

    <Button variant="destructive">Delete</Button>
    

    Geef je de Button-component de opdracht om de rode gevaarstijl te gebruiken, omdat de variant overeenkomt met bg-destructive en text-destructive-foreground.

    Wat zijn “Tailwind-ontwerptokens”?

    “Ontwerptokens” zijn benoemde kleur- en spatiëringsvariabelen die in je hele thema worden gebruikt. In shadcn/ui worden ze als volgt gedefinieerd in je globals.css (of tailwind.config.js):

    :root {
      --background: 0 0% 100%;
      --foreground: 222.2 47.4% 11.2%;
      --primary: 222.2 47.4% 11.2%;
      --primary-foreground: 210 40% 98%;
      --destructive: 0 84.2% 60.2%;
      --destructive-foreground: 210 40% 98%;
      /* etc. */
    }
    

    Tailwind verwijst er vervolgens naar als “tokens” met de theme()-syntaxis of korte klassen:

    className = 'bg-primary text-primary-foreground hover:bg-primary/90'
    

    Deze tokens:

    • Houden kleuren consistent tussen componenten.
    • Ondersteunen automatisch donkere modus via CSS-variabelen.
    • Laten ontwerpers en ontwikkelaars één visuele taal delen (bijvoorbeeld “primary”, “accent”, “destructive”) in plaats van ruwe hexadecimale codes.

    Waarom dit nuttig is

    • Je kunt eenvoudig varianten toevoegen of wijzigen (bijvoorbeeld success, warning) in hetzelfde button.tsx-bestand.
    • Je UI blijft visueel consistent doordat alle varianten gedeelde ontwerptokens gebruiken.
    • Je thema bijwerken (kleuren, spatiëring enzovoort) werkt direct alle componenten bij.
    • Het is flexibel: gebruik de ingebouwde varianten of breid ze uit zodat ze bij je merk passen.

    Kort gezegd: Die varianten (outline, destructive, ghost enzovoort) zijn kant-en-klare stijlen op basis van ontwerptokens die je kunt uitbreiden of overschrijven. Ze dragen eraan bij dat shadcn/ui-componenten standaard klaar zijn voor productie, consistent zijn, rekening houden met thema's en eenvoudig aanpasbaar zijn.

    Voorbeeld 2: dialoogvenster (modaal venster)

    import {
      Dialog,
      DialogContent,
      DialogHeader,
      DialogTitle,
      DialogTrigger,
    } from '@/components/ui/dialog'
    
    export default function Example() {
      return (
        <Dialog>
          <DialogTrigger asChild>
            <Button>Open Dialog</Button>
          </DialogTrigger>
          <DialogContent>
            <DialogHeader>
              <DialogTitle>Confirm Action</DialogTitle>
            </DialogHeader>
            <p>This action cannot be undone.</p>
          </DialogContent>
        </Dialog>
      )
    }
    

    Waarom dit goed werkt: Het dialoogvenster gebruikt Radix-basiscomponenten onder de motorkap, waardoor het standaard met het toetsenbord toegankelijk, geschikt voor schermlezers en responsief is.

    Voorbeeld 3: invoer- en formuliercomponenten

    import { Input } from '@/components/ui/input'
    import { Label } from '@/components/ui/label'
    
    export default function LoginForm() {
      return (
        <form className="space-y-4">
          <div>
            <Label htmlFor="email">Email</Label>
            <Input id="email" type="email" placeholder="you@example.com" />
          </div>
          <Button type="submit">Login</Button>
        </form>
      )
    }
    

    Overzichtelijk, minimaal en eenvoudig uit te breiden voor elke authenticatie- of instellingenpagina.

    Wanneer je shadcn/ui wel en niet moet gebruiken

    ✅ Gebruik het wanneer

    • Je een product op maat bouwt (SaaS, dashboard, app) en snel een consistente UI wilt.
    • Je volledige controle over ontwerp en toegankelijkheid nodig hebt.
    • Je Tailwind CSS en Next.js al gebruikt.

    ❌ Vermijd het wanneer

    • Je de voorkeur geeft aan een direct inzetbaar ontwerpsysteem (zoals MUI, Chakra UI).
    • Je geen Tailwind gebruikt (de koppeling is sterk).
    • Je extreem snel vooruit wilt zonder componentcode aan te raken.

    Aan de slag (snelle configuratie)

    1. Installeer Tailwind CSS (als dat nog niet is gebeurd):

      npx create-next-app my-app
      cd my-app
      npx tailwindcss init -p
      
    2. Initialiseer shadcn/ui

      npx shadcn-ui@latest init
      
    3. Voeg componenten toe

      npx shadcn-ui@latest add button card dialog input
      
    4. Importeer en pas aan Je nieuwe componenten verschijnen in components/ui/.

    🧩 shadcn versus andere UI-bibliotheken

    Kenmerkshadcn/uiChakra UIMaterial UIHeadless UI
    Eigenaarschap van code✅ Jij bent eigenaar❌ Beheerd door de bibliotheek❌ Beheerd door de bibliotheek✅ Jij bent eigenaar
    VormgevingTailwindStyled SystemEmotion / CSSTailwind
    Toegankelijkheid✅ Radix UI✅✅✅
    Thema's✅ (CSS-variabelen + Tailwind)✅✅⚙️ Op maat
    Leercurve🟢 Laag🟢 Gemiddeld🔴 Hoog🟡 Gemiddeld
    Vrijheid in aanpassing🟢 Volledig🟡 Gedeeltelijk🔴 Beperkt🟢 Volledig

    Belangrijkste inzichten

    • shadcn/ui is geen pakket, maar een componentenmodel waarbij je kopieert en eigenaar wordt.
    • Je krijgt echte controle, geen leveranciersafhankelijkheid en een uitstekende ontwikkelervaring.
    • Het is gebouwd met Tailwind, Radix en moderne React-patronen en is ideaal voor teams die een overzichtelijke, toegankelijke en uitbreidbare ontwerpbasis willen.

    Het is de perfecte middenweg tussen “alles zelf bouwen” en “afhankelijk zijn van een zware UI-bibliotheek”.