Bootstrap-track Les 6 van 7

Interactieve componenten

Modals, dropdowns, accordions en toasts — Bootstrap JS doet het werk.

⏱ 30 min 7 stappen Bootstrap 5
Stap 1 / 7

Hoe Bootstrap JS werkt

Interactieve componenten — modals, dropdowns, accordions — werken in Bootstrap 5 bijna zonder dat je zelf JavaScript schrijft. Je voegt speciale data-bs-* attributen toe aan je HTML, en Bootstrap JS regelt de rest.

⬛ Kale HTML + JS
<button id="openBtn">Open modal</button>
<div id="modal" style="display:none">...</div>

<script>
document.getElementById('openBtn')
  .addEventListener('click', () => {
    document.getElementById('modal')
      .style.display = 'block';
  });
</script>

Zelf wiring, styling, backdrop, keyboard support schrijven

🅱️ Bootstrap 5
<button data-bs-toggle="modal"
        data-bs-target="#myModal">
  Open modal
</button>

<div class="modal" id="myModal">
  ...
</div>

Geen eigen JS nodig — Bootstrap regelt alles

📦 bootstrap.bundle.min.js

Interactieve componenten vereisen Bootstrap JS. Laad het altijd voor </body> — het "bundle" bestand bevat ook Popper.js (nodig voor dropdowns en tooltips).

<!-- In <head> — stijlen -->
<link rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css">

<!-- Voor </body> — interactiviteit -->
<script
  src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js">
</script>
De belangrijkste data-bs-* attributen
data-bs-toggle="modal"

Klik opent/sluit een modal

data-bs-target="#id"

Welk element wordt getoggled

data-bs-toggle="dropdown"

Klik opent dropdown-menu

data-bs-toggle="collapse"

Klik klapt element in/uit (accordion)

data-bs-dismiss="modal"

Sluit de huidige modal

data-bs-parent="#id"

Sluit andere items in groep (accordion)

Stap 2 / 7

Modals

Een modal is een dialoogvenster dat bovenop de pagina zweeft. Bootstrap regelt backdrop, animatie, focustrap en keyboard-sluiting (Escape).

Volledige modal structuur
<!-- Trigger knop -->
<button class="btn btn-primary"
        data-bs-toggle="modal"
        data-bs-target="#bevestigModal">
  Verwijder account
</button>

<!-- Modal HTML (buiten andere containers, voor </body>) -->
<div class="modal fade" id="bevestigModal" tabindex="-1">
  <div class="modal-dialog">
    <div class="modal-content">

      <div class="modal-header">
        <h5 class="modal-title">Weet je het zeker?</h5>
        <button type="button" class="btn-close"
                data-bs-dismiss="modal"></button>
      </div>

      <div class="modal-body">
        <p>Dit kan niet ongedaan worden gemaakt.</p>
      </div>

      <div class="modal-footer">
        <button class="btn btn-secondary"
                data-bs-dismiss="modal">Annuleren</button>
        <button class="btn btn-danger">Verwijderen</button>
      </div>

    </div>
  </div>
</div>
Grootte varianten
modal-sm — 300px
(default) — 500px
modal-lg — 800px
modal-xl — 1140px
modal-fullscreen — volledig scherm
<div class="modal-dialog modal-lg">
Gecentreerd
<div class="modal-dialog
  modal-dialog-centered">

Modal wordt verticaal gecentreerd in het scherm

Scrollable inhoud
<div class="modal-dialog
  modal-dialog-scrollable">

Body scrollt, header/footer blijven vast

💡 Programmatisch aansturen

Soms wil je een modal vanuit JavaScript openen (bijv. na een fetch-call):

// Haal Bootstrap-instantie op en gebruik .show() / .hide()
const modalEl = document.getElementById('bevestigModal');
const modal = new bootstrap.Modal(modalEl);

modal.show();   // openen
modal.hide();   // sluiten
▶ Live voorbeeld — klik "Uitvoeren"
Stap 3 / 7

Dropdowns

Een dropdown toont een menu op klik. Bootstrap gebruikt Popper.js (ingebouwd in het bundle-bestand) voor de positionering.

Basis dropdown
<div class="dropdown">
  <button class="btn btn-secondary dropdown-toggle"
          data-bs-toggle="dropdown">
    Acties
  </button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Bewerken</a></li>
    <li><a class="dropdown-item" href="#">Dupliceren</a></li>
    <li><hr class="dropdown-divider"></li>
    <li><a class="dropdown-item text-danger" href="#">Verwijderen</a></li>
  </ul>
</div>
Richting
dropdown — naar beneden (default)
dropup — naar boven
dropend — naar rechts
dropstart — naar links
<div class="dropup">...</div>
Split button dropdown
<div class="btn-group">
  <button class="btn btn-primary">
    Opslaan
  </button>
  <button class="btn btn-primary
    dropdown-toggle
    dropdown-toggle-split"
    data-bs-toggle="dropdown">
  </button>
  <ul class="dropdown-menu">...</ul>
</div>
▶ Live voorbeeld
Stap 4 / 7

Accordion

Een accordion klapt secties open en dicht. Ideaal voor FAQ's, instellingen of uitgebreide navigatie. Elke sectie bestaat uit een header (knop) en een collapsible body.

Accordion structuur
<div class="accordion" id="faqAccordion">

  <!-- Item 1 -->
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button"
              data-bs-toggle="collapse"
              data-bs-target="#vraag1">
        Wat is Bootstrap?
      </button>
    </h2>
    <div id="vraag1" class="accordion-collapse collapse show"
         data-bs-parent="#faqAccordion">
      <div class="accordion-body">
        Bootstrap is een CSS-framework...
      </div>
    </div>
  </div>

  <!-- Item 2 -->
  <div class="accordion-item">
    <h2 class="accordion-header">
      <button class="accordion-button collapsed"
              data-bs-toggle="collapse"
              data-bs-target="#vraag2">
        Werkt het met Symfony?
      </button>
    </h2>
    <div id="vraag2" class="accordion-collapse collapse"
         data-bs-parent="#faqAccordion">
      <div class="accordion-body">
        Ja, via bootstrap_5_layout.html.twig...
      </div>
    </div>
  </div>

</div>
Belangrijk detail
  • collapse show — item begint open
  • collapse — item begint dicht
  • collapsed op knop — knop-stijl voor dicht item
  • data-bs-parent="#id" — alleen één item tegelijk open
Zonder data-bs-parent

Laat data-bs-parent weg als je meerdere items tegelijk open wilt kunnen hebben.

Handig voor lange instellingspagina's waar de gebruiker meerdere secties wil vergelijken.

▶ Live voorbeeld
Stap 5 / 7

Toasts

Toasts zijn korte meldingen die even verschijnen en dan verdwijnen — vergelijkbaar met Symfony flash messages, maar dan client-side.

Toast HTML
<div class="toast-container position-fixed bottom-0 end-0 p-3">
  <div id="mijnToast" class="toast" role="alert">
    <div class="toast-header">
      <strong class="me-auto">Melding</strong>
      <small>Nu</small>
      <button type="button" class="btn-close"
              data-bs-dismiss="toast"></button>
    </div>
    <div class="toast-body">
      Opgeslagen! ✓
    </div>
  </div>
</div>
💡 Toasts zijn standaard verborgen

Je moet een toast programmatisch tonen met JavaScript:

// Toon een toast na een actie (bijv. formulier opgeslagen)
function toonToast(id) {
  const toastEl = document.getElementById(id);
  const toast = new bootstrap.Toast(toastEl);
  toast.show();
}

// Optie: automatisch verdwijnen instellen (in ms)
const toast = new bootstrap.Toast(toastEl, { delay: 3000 });
🎵 Komt terug in Symfony

Symfony flash messages (app.flashes()) zijn server-side — de pagina reloadt. Bootstrap Toasts zijn client-side — geen reload nodig. Combineer ze voor de beste UX:

{# In Twig: flash messages als Bootstrap toasts #}
{% for message in app.flashes('success') %}
<div id="flashToast-{{ loop.index }}" class="toast align-items-center text-bg-success border-0" role="alert">
  <div class="d-flex">
    <div class="toast-body">{{ message }}</div>
    <button type="button" class="btn-close btn-close-white me-2 m-auto"
            data-bs-dismiss="toast"></button>
  </div>
</div>
{% endfor %}

<script>
// Auto-toon alle flash toasts
document.querySelectorAll('.toast').forEach(el => {
  new bootstrap.Toast(el, { delay: 4000 }).show();
});
</script>
▶ Live voorbeeld
Stap 6 / 7

Oefening 1 — Productpagina

🎯 Opdracht

Bouw een productdetailpagina met:

  • Een dropdown knop "Kleur kiezen" met 3 opties
  • Een knop "Meer info" die een modal opent met producttekst
  • Een knop "In winkelwagen" die een groene toast toont ("Toegevoegd!")

Tip: je hebt data-bs-toggle, data-bs-target, en new bootstrap.Toast() nodig.

Oplossing tonen
<div class="d-flex gap-2 flex-wrap mb-3">

  <!-- Dropdown -->
  <div class="dropdown">
    <button class="btn btn-outline-secondary dropdown-toggle" data-bs-toggle="dropdown">
      Kleur kiezen
    </button>
    <ul class="dropdown-menu">
      <li><a class="dropdown-item" href="#">Zwart</a></li>
      <li><a class="dropdown-item" href="#">Wit</a></li>
      <li><a class="dropdown-item" href="#">Blauw</a></li>
    </ul>
  </div>

  <!-- Modal trigger -->
  <button class="btn btn-info" data-bs-toggle="modal" data-bs-target="#infoModal">Meer info</button>

  <!-- Toast trigger -->
  <button class="btn btn-success" onclick="new bootstrap.Toast(document.getElementById('cartToast'),{delay:3000}).show()">
    In winkelwagen
  </button>

</div>

<!-- Modal -->
<div class="modal fade" id="infoModal" tabindex="-1">
  <div class="modal-dialog modal-dialog-centered">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title">Productinformatie</h5>
        <button class="btn-close" data-bs-dismiss="modal"></button>
      </div>
      <div class="modal-body">
        <p>Materiaal: aluminium behuizing. Gewicht: 1.2 kg. Garantie: 2 jaar.</p>
      </div>
      <div class="modal-footer">
        <button class="btn btn-secondary" data-bs-dismiss="modal">Sluiten</button>
      </div>
    </div>
  </div>
</div>

<!-- Toast -->
<div class="toast-container position-fixed bottom-0 end-0 p-3">
  <div id="cartToast" class="toast align-items-center text-bg-success border-0">
    <div class="d-flex">
      <div class="toast-body">Toegevoegd aan winkelwagen!</div>
      <button class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast"></button>
    </div>
  </div>
</div>
Stap 7 / 7

Oefening 2 — FAQ-pagina

🎯 Opdracht

Bouw een FAQ-pagina met:

  • Een accordion met 4 vragen (waarvan de eerste standaard open is)
  • Een navbar met een dropdown "Meer" met twee links
  • Alles in een container, mooi opgemaakt
Oplossing tonen
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
  <div class="container">
    <a class="navbar-brand" href="#">MijnSite</a>
    <div class="navbar-nav ms-auto">
      <a class="nav-link" href="#">Home</a>
      <a class="nav-link active" href="#">FAQ</a>
      <div class="nav-item dropdown">
        <a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">Meer</a>
        <ul class="dropdown-menu">
          <li><a class="dropdown-item" href="#">Over ons</a></li>
          <li><a class="dropdown-item" href="#">Contact</a></li>
        </ul>
      </div>
    </div>
  </div>
</nav>

<div class="container py-5">
  <h1 class="mb-4">Veelgestelde vragen</h1>
  <div class="accordion" id="faq">
    <div class="accordion-item">
      <h2 class="accordion-header">
        <button class="accordion-button" data-bs-toggle="collapse" data-bs-target="#q1">Vraag 1</button>
      </h2>
      <div id="q1" class="accordion-collapse collapse show" data-bs-parent="#faq">
        <div class="accordion-body">Antwoord 1</div>
      </div>
    </div>
    <!-- herhaal voor q2, q3, q4 -->
  </div>
</div>

🧠 Kennischeck

Les 6 afgerond!

Je beheerst modals, dropdowns, accordions en toasts — de interactieve kern van Bootstrap.

Les 7: Aanpassen & best practices →