Modal — Vanilla

Modal dialog with vanilla HTML + JS. Same BEM and sizes as Astro/Svelte. Ensure Rizzo CSS is loaded.

Modal

Dialog with overlay, focus trap, and optional sizes (sm, md, lg). Same structure as Astro and Svelte.

Add this component

The command below includes <strong>Modal</strong>—run it in your project directory to install this component (and the CSS if needed). No prompts.

Choose your package manager — click a tab to select, then copy the command.

npm pnpm yarn bun

Modal sizes

Small (24rem), medium (32rem), large (48rem). Click to open:

Live examples

Standard example

Live example

Click the button below to open a standard modal dialog:

HTML

Use modal__overlay (sibling) and modal with modal__header, modal__body, modal__footer. Size: modal--sm, modal--md, modal--lg.

html html
<button type="button" class="btn btn-primary" id="open-modal-btn">Open Example Modal</button>

<!-- Use .modal-root so overlay stacks behind the modal. Overlay id: <modalId>-overlay. -->
<div class="modal-root">
  <div class="modal__overlay" id="demo-overlay" aria-hidden="true"></div>
  <div class="modal modal--md" id="demo-modal" role="dialog" aria-modal="true" aria-labelledby="demo-modal-title" aria-hidden="true">
    <div class="modal__header">
      <h2 class="modal__title" id="demo-modal-title">Example Modal</h2>
      <button type="button" class="modal__close" aria-label="Close modal">×</button>
    </div>
    <div class="modal__body">
      <p>This is an example modal dialog. It demonstrates:</p>
      <ul>
        <li>Focus trapping — Tab cycles within the modal</li>
        <li>Keyboard navigation — Escape key closes the modal</li>
        <li>Backdrop overlay with blur effect</li>
        <li>Theme-aware styling</li>
      </ul>
    </div>
    <div class="modal__footer">
      <button type="button" class="btn">Cancel</button>
      <button type="button" class="btn btn-primary">Confirm</button>
    </div>
  </div>
</div>

JavaScript

javascript javascript
(function() {
  var openBtn = document.getElementById('open-modal-btn');
  var overlay = document.getElementById('demo-overlay');
  var modal = document.getElementById('demo-modal');
  if (!openBtn || !overlay || !modal) return;

  function openModal() {
    overlay.setAttribute('aria-hidden', 'false');
    modal.setAttribute('aria-hidden', 'false');
    document.body.style.overflow = 'hidden';
  }
  function closeModal() {
    overlay.setAttribute('aria-hidden', 'true');
    modal.setAttribute('aria-hidden', 'true');
    document.body.style.overflow = '';
  }

  openBtn.addEventListener('click', openModal);
  overlay.addEventListener('click', closeModal);
  modal.querySelector('.modal__close').addEventListener('click', closeModal);
  document.addEventListener('keydown', function(e) {
    if (e.key === 'Escape' && modal.getAttribute('aria-hidden') === 'false') closeModal();
  });
})();

Other frameworks: Astro ¡ Svelte ¡ Vue ¡ React