Custom componenten bouwen met Hyvä UI
Terug naar blog

Custom componenten bouwen met Hyvä UI

AuthorRuthger Idema
21 mei 20267 min leestijd

Hyvä UI levert tientallen kant-en-klare componenten, maar vroeg of laat wil je iets dat er niet tussen zit. Dan bouw je zelf een component in exact dezelfde stijl: Tailwind-classes, Alpine.js voor interactie, geen build-step voor JavaScript. Dit artikel laat zien hoe je dat doet, stap voor stap.

Custom componenten bouwen met Hyvä UI

Hyvä UI levert tientallen kant-en-klare componenten, maar vroeg of laat wil je iets dat er niet tussen zit. Dan bouw je zelf een component in exact dezelfde stijl: Tailwind-classes, Alpine.js voor interactie, geen build-step voor JavaScript. Dit artikel laat zien hoe je dat doet, stap voor stap.

Wat is Hyvä UI precies?

Hyvä UI is het officiële design system en de componentbibliotheek van het Hyvä-ecosysteem. Het is gebouwd op Tailwind CSS en Alpine.js, HTML-first, met minimale JavaScript.

Belangrijk onderscheid: Hyvä UI is niet hetzelfde als een Hyvä theme. Een Hyvä theme vervangt de volledige Magento 2 frontend (Luma, RequireJS, jQuery, Knockout). Hyvä UI is een losse componentbibliotheek. Je kunt hem gebruiken in Magento 2 met Hyvä theme, maar ook in Laravel, headless-setups of statische sites. Framework-agnostisch.

De bibliotheek bevat onder andere: buttons, forms, modals, dropdowns, accordions, navigatie, tabs en product cards. De prijs is eenmalig ongeveer 250 euro per-ontwikkelaar/projectlicentie, geen abonnement. Er is ook een Figma Community-bestand bijgeleverd: design tokens en componenten die 1-op-1 matchen met de code.

Meer achtergrond over het volledige design system lees je op onze Hyvä UI-pagina.

De filosofie achter een custom Hyvä UI-component

Voordat je begint: begrijp de twee regels die elk Hyvä UI-component volgt.

  1. HTML-first. Structuur en stijl zitten in de markup, niet in een JavaScript-module.
  2. Alpine.js alleen voor interactie. State, events en eenvoudige DOM-manipulatie. Niet voor data-fetching of business logic.

Als je die twee regels aanhoudt, gedraagt jouw custom component zich identiek aan de meegeleverde componenten. Dat is belangrijk voor consistentie in het team en voor performance.

Hyvä scoort ~95% minder JavaScript dan Luma. Dat vertaalt zich naar Lighthouse-scores van 95+. Die winst verdwijnt zodra je Alpine.js gaat gebruiken voor dingen die CSS al kan, of wanneer je een externe JavaScript-library inlaadt voor iets triviaals.

Stap 1: design tokens en Tailwind-config

Hyvä UI werkt met design tokens. Kleuren, spacing en typography zijn gedefinieerd in de Tailwind-config, niet hard-coded in de componenten. Controleer eerst of jouw tailwind.config.js de Hyvä-tokens bevat.

Een minimale setup ziet er zo uit:

js
// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.html',
    './src/**/*.php',
    './src/**/*.phtml',
  ],
  theme: {
    extend: {
      colors: {
        primary: {
          DEFAULT: '#1a56db',
          light: '#3f83f8',
          dark: '#1e429f',
        },
        secondary: {
          DEFAULT: '#0e9f6e',
          light: '#31c48d',
          dark: '#057a55',
        },
      },
      fontFamily: {
        sans: ['Inter', 'ui-sans-serif', 'system-ui'],
      },
    },
  },
  plugins: [],
}

Gebruik je het Figma Community-bestand, dan staan de exacte token-waarden daar in. Zo synchroniseer je design en code zonder handmatig overtikken.

Stap 2: de component structureren

We bouwen een notification banner: een opvallende balk die bovenaan de pagina verschijnt met een bericht, en die de gebruiker weg kan klikken. Simpel genoeg om te begrijpen, complex genoeg om de patronen te laten zien.

Componenten in Hyvä UI volgen altijd dezelfde structuur:

LaagVerantwoordelijkheidTechnologie
MarkupStructuur en semantiekHTML
StijlVisuele presentatieTailwind CSS
InteractieState en eventsAlpine.js
DataInhoud en configuratiePHP/Blade/template

Zo ziet de component eruit:

html
<!-- Notification Banner Component -->
<div
  x-data="notificationBanner({ autoClose: 5000 })"
  x-show="visible"
  x-transition:enter="transition ease-out duration-300"
  x-transition:enter-start="opacity-0 -translate-y-2"
  x-transition:enter-end="opacity-100 translate-y-0"
  x-transition:leave="transition ease-in duration-200"
  x-transition:leave-start="opacity-100 translate-y-0"
  x-transition:leave-end="opacity-0 -translate-y-2"
  role="alert"
  class="relative flex items-center justify-between gap-4 px-4 py-3 text-sm font-medium text-white bg-primary rounded-lg shadow-md"
>
  <!-- Icon -->
  <div class="flex items-center gap-2 min-w-0">
    <svg class="w-5 h-5 shrink-0" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
      <path fill-rule="evenodd"
        d="M18 10A8 8 0 1 1 2 10a8 8 0 0 1 16 0zm-7-4a1 1 0 1 1-2 0 1 1 0 0 1 2 0zm-1 9a1 1 0 0 1-1-1V9a1 1 0 1 1 2 0v4a1 1 0 0 1-1 1z"
        clip-rule="evenodd" />
    </svg>
    <!-- Message slot -->
    <p class="truncate" x-text="message"></p>
  </div>

  <!-- Close button -->
  <button
    @click="close()"
    type="button"
    class="shrink-0 p-1 rounded hover:bg-white/20 focus:outline-none focus:ring-2 focus:ring-white/50 transition-colors"
    aria-label="Sluiten"
  >
    <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
      <path fill-rule="evenodd"
        d="M4.293 4.293a1 1 0 0 1 1.414 0L10 8.586l4.293-4.293a1 1 0 1 1 1.414 1.414L11.414 10l4.293 4.293a1 1 0 0 1-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L8.586 10 4.293 5.707a1 1 0 0 1 0-1.414z"
        clip-rule="evenodd" />
    </svg>
  </button>
</div>

Stap 3: de Alpine.js component schrijven

De JavaScript-functie hoort in een apart