Skip to content
Components

Dialog & drawer

Modal dialogs and slide-in drawers built on the native `<dialog>` element with `@starting-style` animations.

Stable Keyboard Screen reader Evergreen
Confirm action

Are you sure you want to continue? This cannot be undone.

html
<button class="b-btn" data-b-toggle="dialog" data-b-target="#confirm">Open</button>

<dialog id="confirm" class="b-modal">
  <div class="b-card-header">
    <strong>Title</strong>
    <button class="b-close" data-b-dismiss="dialog">×</button>
  </div>
  <div class="b-card-body">...</div>
  <div class="b-card-footer">
    <button class="b-btn b-btn-ghost" data-b-dismiss="dialog">Cancel</button>
    <button class="b-btn">Confirm</button>
  </div>
</dialog>

Drawer

Filters
Drawer content
Settings
Drawer content
html
<dialog class="b-drawer" data-side="right">...</dialog>

Sides: data-side="right" (default left), data-side="bottom".

Animations

Modals and drawers use native @starting-style for entry animations — fading in for modals, sliding for drawers. Honors prefers-reduced-motion.

Scroll lock

showModal() traps focus but leaves the page behind the backdrop scrollable. BlastCSS locks it in CSS:

css
html:has(.b-modal[open], .b-drawer[open], .b-command[open]) { overflow: hidden; }

Because it is a selector rather than a JS hook, it applies to any dialog you open — including ones opened by your own code rather than data-b-toggle. The reset sets scrollbar-gutter: stable on html so locking does not shift the layout.

API

ComponentClass
Modal dialog<dialog class="b-modal">
Drawer<dialog class="b-drawer"> (data-side controls direction)
Toggledata-b-toggle="dialog" data-b-target="#id"
Dismissdata-b-dismiss="dialog" (inside the dialog)

The bundled JS auto-traps Tab focus inside open dialogs.

Edit this page