Alpine.js patterns in Hyvä UI
Terug naar blog

Alpine.js patterns in Hyvä UI

AuthorRuthger Idema
25 mei 20267 min leestijd

Hyvä UI levert componenten die werken zonder build-step, zonder Webpack-config en zonder npm-scripts. De reden: Alpine.js als enige JavaScript-laag, precies zo ingezet als Hyvä het bedoeld heeft. In dit artikel laten we zien welke patronen terugkomen, hoe reactivity werkt en waar de grenzen liggen.

Alpine.js patterns in Hyvä UI

Hyvä UI levert componenten die werken zonder build-step, zonder Webpack-config en zonder npm-scripts. De reden: Alpine.js als enige JavaScript-laag, precies zo ingezet als Hyvä het bedoeld heeft. In dit artikel laten we zien welke patronen terugkomen, hoe reactivity werkt en waar de grenzen liggen.

Wat Alpine.js doet in Hyvä UI

Alpine.js is geen framework in de klassieke zin. Het is een declaratieve laag die je direct in HTML schrijft. Geen virtual DOM, geen component-files, geen bundler vereist.

Hyvä UI bouwt daar consequent op voort. Elke component is een stuk HTML met Alpine-attributen. Je kopieert de markup, plakt hem in je template en het werkt.

De vier attributen die je het meest tegenkomt:

  • x-data — definieert de lokale state van een component
  • x-show / x-if — conditionele rendering
  • @click / @keydown — event-handlers
  • x-bind / :class — dynamische classes en attributen

Dat is het. Geen reducers, geen stores, geen lifecycle-hooks tenzij je ze zelf nodig hebt.

x-data: lokale state per component

x-data is het startpunt van elke interactieve component in Hyvä UI. Je definieert er een JavaScript-object mee dat lokaal is aan dat element en zijn children.

Voorbeeld: een accordion die open en dicht klapt.

html
<div x-data="{ open: false }">
  <button @click="open = !open" class="w-full text-left font-semibold py-3">
    Vraag: wat kost Hyvä UI?
    <span :class="open ? 'rotate-180' : ''" class="transition-transform inline-block"></span>
  </button>
  <div x-show="open" x-transition class="text-gray-600 pb-4">
    Eenmalig ongeveer 250 euro, per-ontwikkelaar/projectlicentie. Geen abonnement.
  </div>
</div>

Dit is precies hoe de accordion-component in Hyvä UI werkt. Geen externe file, geen import. State leeft in de markup zelf.

Voor complexere componenten, zoals een modal met meerdere triggers, verplaats je de logica naar een x-data-functie:

html
<div x-data="modal()">
  <button @click="open()">Open modal</button>

  <div x-show="isOpen" @click.away="close()" class="fixed inset-0 bg-black/50 flex items-center justify-center">
    <div class="bg-white rounded-lg p-6 max-w-md w-full">
      <button @click="close()" class="float-right text-gray-400 hover:text-gray-600"></button>
      <slot></slot>
    </div>
  </div>
</div>

<script>
function modal() {
  return {
    isOpen: false,
    open() { this.isOpen = true },
    close() { this.isOpen = false },
  }
}
</script>

De functie modal() definieer je eenmalig en hergebruik je overal. Geen ES-modules nodig.

x-show vs x-if: wanneer gebruik je wat?

Een veelgestelde vraag. Het verschil is klein maar relevant voor performance.

AttribuutWerkingGebruik wanneer
x-showZet display: none via CSSElement wordt frequent getoond/verborgen
x-ifVoegt element toe/verwijdert het uit de DOMElement is zelden zichtbaar of bevat zware markup

Hyvä UI gebruikt x-show voor modals, dropdowns en accordions. De reden: CSS-transities werken alleen als het element in de DOM aanwezig is. Met x-if vervalt x-transition.

Voor product cards met lazy-loaded afbeeldingen of content die zelden wordt getoond, is x-if de juiste keuze. Minder DOM, betere Lighthouse-score.

Events en component-communicatie

Alpine.js heeft een ingebouwd event-systeem via $dispatch en @. Hyvä UI gebruikt dit voor communicatie tussen componenten die geen gedeelde parent hebben.

Voorbeeld: een "voeg toe aan winkelwagen"-knop die een toast-notificatie triggert elders op de pagina.

html
<!-- Knop (ergens in product card) -->
<button @click="$dispatch('cart:added', { name: 'Product X' })">
  In winkelwagen
</button>

<!-- Toast (in header of body) -->
<div
  x-data="{ show: false, message: '' }"
  @cart:added.window="show = true; message = $event.detail.name; setTimeout(() => show = false, 3000)"
  x-show="show"
  class="fixed bottom-4 right-4 bg-green-600 text-white px-4 py-2 rounded shadow-lg"
>
  <span x-text="message"></span> toegevoegd aan winkelwagen.
</div>
.window op de event-listener zorgt dat het event op window-niveau wordt gevangen. Zo communiceren twee losstaande Alpine-instanties zonder gedeelde state of parent-component.

Dit patroon zie je in de Hyvä UI navigatie- en notificatie-componenten. Het houdt de structuur flat en vermijdt prop-drilling.

Reactivity zonder build-step

Het krachtige van Alpine.js is dat reactivity automatisch werkt. Je muteert state, de DOM updatet. Geen setState, geen ref, geen watcher nodig voor simpele gevallen.

html
<div x-data="{ count: 0, doubled: 0 }" x-init="$watch('count', val => doubled = val * 2)">
  <button @click="count++">+</button>
  <p>Count: <span x-text="count"></span></p>
  <p>Dubbel: <span x-text="doubled"></span></p>
</div>
$watch is een Alpine-magic property die een waarde observeert en een callback aanroept bij wijziging. Handig voor afgeleide waarden, validatie of API-calls die afhangen van state.

Wij zien bij klanten dat dit patroon 80% van de interactieve frontend-behoeften dekt. Tabs, filters, toggles, accordions, modals: allemaal oplosbaar met x-data + x-show + @event.

Tabs en navigatie: een concreet patroon

De tab-component uit Hyvä UI combineert meerdere Alpine-patronen:

html
<div x-data="{ active: 'beschrijving' }">
  <!-- Tabs nav -->
  <div class="flex border-b border-gray-200">
    <button
      @click="active = 'beschrijving'"
      :class="active === 'beschrijving' ? 'border-b-2 border-blue-600 text-blue-600' : 'text-gray-500'"
      class="px-4 py-2 text-sm font-medium"
    >
      Beschrijving
    </button>
    <button
      @click="active = 'specs'"
      :class="active === 'specs' ? 'border-b-2 border-blue-600 text-blue-600' : 'text-gray-500'"
      class="px-4 py-2 text-sm font-medium"
    >
      Specificaties
    </button>
  </div>

  <!-- Tab content -->
  <div x-show="active === 'beschrijving'" class="py-4">
    <p>Productbeschrijving hier.</p>
  </div>
  <div x-show="active === 'specs'" class="py-4">
    <p>Specificaties hier.</p>
  </div>
</div>

Eén x-data op de container. Knoppen lezen en schrijven active. Content reageert via x-show. Geen externe state manager, geen component-lifecycle.

Dit is ook precies de reden dat Hyvä UI framework-agnostisch is. Dezelfde markup werkt in Magento 2 Hyvä-templates, Laravel Blade-bestanden, headless setups of statische HTML. Geen aanpassingen nodig.

Meer over het bouwen van eigen componenten bovenop deze patronen: Hyvä UI custom componenten bouwen.

Performance: waarom dit relevant is

Hyvä UI is gebouwd op de performance-filosofie van Hyvä zelf: ~95% minder JavaScript dan Luma. Alpine.js weegt gzipped minder dan 15 kB. Tailwind CSS genereert alleen gebruikte classes (tree-shaken in productie).

Het resultaat: Lighthouse-scores van 95+ zijn haalbaar zonder heroïsche optimalisaties. Wij zien dat bij Magento 2-shops die van Luma naar Hyvä migreren de Time to Interactive met 60-70% daalt.

Dat heeft direct impact op conversie. Google's eigen data: elke seconde laadtijdverbetering verhoogt conversie met 2-4%.

Wanneer Hyvä UI niet de juiste keuze is

Eerlijk zijn: er zijn gevallen waar Hyvä UI niet de beste keuze is.

  • React of Vue frontends: als je een headless setup hebt met een JavaScript-framework, gebruik dan de component-library van dat framework. Alpine.js naast React mengen is geen goed idee.
  • Zeer complexe frontend-state: een uitgebreide checkout met meerdere stappen, real-time validatie en afhankelijkheden tussen velden vraagt op een bepaald punt om een echte state-manager. Alpine.js heeft Alpine.store() voor globale state, maar is geen vervanging voor Pinia of Redux in zware applicaties.
  • Bestaande Luma-thema's bijwerken: Hyvä UI is HTML-first en Tailwind-based. Een bestaand Luma-thema heeft andere CSS-methodologie en JavaScript-architectuur. De componenten plakken in Luma lost meer problemen dan het creëert, maar vraagt extra integratie-werk.
  • Teams zonder Alpine.js-kennis: de leercurve is laag, maar bestaat. Een team dat puur in React denkt heeft een dag inwerkperiode nodig.

Voor de gevallen waar Hyvä UI wel past, is het de snelste route van design naar productie die wij kennen in de Magento 2 + Hyvä-stack.

Figma en code: één bron van waarheid

Hyvä UI bevat een Figma Community-bestand met design tokens en componenten die 1-op-1 matchen met de code. Dat is zeldzaam.

In de praktijk betekent dit: als een designer een button aanpast in Figma, gebruikt hij dezelfde tokens als de developer in Tailwind. Geen vertaalslag, geen interpretatieproblemen.

Voor teams met een designer en een developer is dit direct tijdwinst. Wij zien in projecten dat dit de feedback-loop tussen design en implementatie met 40-50% verkort.

Hyvä UI vs een Hyvä theme: het onderscheid

Dit blijft een bron van verwarring. Twee duidelijke definities:

Hyvä theme: de volledige Magento 2 frontend die Luma (RequireJS, jQuery, Knockout.js) vervangt. Dit is de basis van een moderne Magento 2-shop. Aparte licentie, aparte setup. Hyvä UI: een losse componentbibliotheek. Buttons, forms, modals, dropdowns, accordions, navigatie, tabs, product cards. Bruikbaar bovenop een Hyvä theme, maar ook in Laravel, headless of statische sites. Eenmalig ongeveer 250 euro, per-ontwikkelaar/projectlicentie, geen abonnement.

Je hebt geen Hyvä theme nodig om Hyvä UI te gebruiken. En een Hyvä theme zonder Hyvä UI is ook prima, maar je begint dan de componenten zelf te schrijven.

Meer over de volledige Hyvä-stack: Hyvä UI overzicht.

Conclusie

Alpine.js patronen in Hyvä UI zijn geen magie. Het zijn vier attributen — x-data, x-show, @event, :class — consequent toegepast op HTML-first componenten. Geen build-step, geen bundler, geen framework-overhead.

Voor Magento 2 Hyvä-projecten is dit de standaard geworden bij ons. Voor Laravel en headless projecten is het een serieuze optie die we vaker inzetten dan verwacht.

Wil je weten of Hyvä UI past bij jouw specifieke project? Wij kijken graag mee. Neem contact op via /contact voor een gratis Tech Check — geen verkooppraatje, gewoon een eerlijk technisch gesprek.

Ruthger Idema

Geschreven door Ruthger Idema

15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.

Meer over ons team →
Deel dit artikel:

Wil je jouw e-commerce naar het volgende niveau?

Plan een vrijblijvend gesprek met onze experts over Magento, Shopify of Laravel maatwerk.

Plan een Tech Check