Dialog

v0.0.10

v0.0.10StableHeadlessStatelessAccessibleJSApache-2.0
Installation mix mishka.ui.gen.headless dialog
Source View Source

Overview of the Phoenix and LiveView Headless Dialog Component

The Mishka Chelekom Headless Dialog ships zero opinionated styling - only the semantic markup, full WAI-ARIA wiring, a focus trap, scroll lock, and paired-presence state (data-open/data-closed). Every part - trigger, backdrop, viewport, popup, title, description, content and footer - is addressable through a *_class attribute, so you style it entirely with your own Tailwind classes while the accessibility and behavior keep working underneath.

Base UI Dialog example (Phoenix headless)

Base UI Dialog example (Phoenix headless)

heex
<.dialog
  id="baseui-dialog-hero"
  trigger_class="flex h-8 items-center justify-center gap-2 border border-neutral-950 dark:border-white bg-white dark:bg-neutral-950 px-3 text-sm font-normal text-neutral-950 dark:text-white select-none hover:bg-neutral-100 dark:hover:bg-neutral-800"
  backdrop_class="fixed inset-0 min-h-dvh bg-black opacity-20 transition-opacity duration-150 data-[ending-style]:opacity-0 data-[starting-style]:opacity-0 dark:opacity-50"
  popup_class="fixed top-1/2 left-1/2 -mt-8 flex w-96 max-w-[calc(100vw-3rem)] -translate-x-1/2 -translate-y-1/2 flex-col gap-4 bg-white dark:bg-neutral-950 p-4 text-neutral-950 dark:text-white border border-neutral-950 dark:border-white shadow-[0.25rem_0.25rem_0] shadow-black/12 transition-[scale,opacity] duration-100 ease-out data-[ending-style]:scale-[0.98] data-[ending-style]:opacity-0 data-[starting-style]:scale-[0.98] data-[starting-style]:opacity-0"
  title_class="text-base font-bold"
  description_class="text-sm text-neutral-600 dark:text-neutral-400"
  footer_class="flex justify-end gap-3"
>
  <:trigger>View notifications</:trigger>
  <:title>Notifications</:title>
  <:description>You are all caught up. Good job!</:description>
  <p class="text-sm text-neutral-600 dark:text-neutral-400">Your next summary arrives on Monday.</p>
  <:close>
    <button
      type="button"
      data-close
      class="flex h-8 items-center gap-2 border border-neutral-950 dark:border-white bg-white dark:bg-neutral-950 px-3 text-sm text-neutral-950 dark:text-white hover:bg-neutral-100 dark:hover:bg-neutral-800"
    >
      Close
    </button>
  </:close>
</.dialog>

Parts & data attributes

Each part carries a stable data-part and a structural chelekom-dialog__* class you can target, plus paired-presence state for open/closed transitions.

Partdata-partState / ARIAPurpose
Triggertriggeraria-haspopup, aria-expanded, data-popup-openThe button that opens the dialog.
Backdropbackdropdata-open, data-closed, data-starting-style, data-ending-styleThe overlay behind the popup; carries the transition state.
Popuppopuprole="dialog", focus-trappedThe dialog panel itself.
Title / Descriptiontitle / descriptionaria-labelledby / aria-describedbyAnnounced to screen readers; wired automatically.

Accessibility

Follows the WAI-ARIA Dialog (Modal) pattern: focus is trapped inside the open dialog and restored to the trigger on close, Escape closes it, and an outside click dismisses it (both configurable). The title and description slots are announced to screen readers.