Basic Modal
A titled dialog with a focus trap, Escape to close and focus returned to the trigger.
6 frameworksIntermediate
A multi-step wizard in one dialog with progress dots, Back/Next and a Finish on the last step.
<!--
A multi-step wizard inside one dialog. Back is disabled on the first step and
the primary button becomes Finish on the last. The step region is aria-live so
each change is announced, and the progress is not colour-only - the active dot
is wider. The dialog keeps its focus trap and Escape throughout. This markup
shows one step; the React versions advance with state.
-->
<div class="fixed inset-0 z-50 flex items-center justify-center p-4">
<div class="absolute inset-0 bg-black/50" data-modal-close></div>
<div role="dialog" aria-modal="true" aria-labelledby="wiz-modal-title" class="relative max-h-[calc(100dvh-2rem)] w-full max-w-md overflow-y-auto rounded-2xl border border-gray-200 bg-white p-6 shadow-2xl dark:border-gray-800 dark:bg-gray-900">
<div class="flex items-center justify-between">
<div class="flex items-center gap-1.5" aria-hidden="true">
<span class="h-1.5 w-5 rounded-full bg-blue-600 dark:bg-blue-400"></span>
<span class="h-1.5 w-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></span>
<span class="h-1.5 w-1.5 rounded-full bg-gray-300 dark:bg-gray-700"></span>
</div>
<button type="button" aria-label="Close" data-modal-close class="inline-flex h-10 w-10 items-center justify-center rounded-lg text-gray-500 hover:bg-gray-100 hover:text-gray-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:text-gray-400 dark:hover:bg-gray-800 dark:hover:text-gray-100 dark:focus-visible:ring-blue-400 dark:focus-visible:ring-offset-gray-900">
<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true" focusable="false"><path d="M18 6 6 18M6 6l12 12" /></svg>
</button>
</div>
<div class="mt-4" aria-live="polite">
<p class="text-xs font-semibold uppercase tracking-wide text-blue-700 dark:text-blue-400">Step 1 of 3</p>
<h2 id="wiz-modal-title" class="mt-1 text-lg font-semibold text-gray-900 dark:text-gray-100">Welcome aboard</h2>
<p class="mt-2 text-sm leading-relaxed text-gray-600 dark:text-gray-400">A quick three-step setup gets your workspace ready. It takes under a minute.</p>
</div>
<div class="mt-6 flex items-center justify-between gap-2">
<button type="button" disabled class="rounded-lg border border-gray-300 bg-white px-4 py-2 text-sm font-semibold text-gray-700 disabled:cursor-not-allowed disabled:opacity-40 dark:border-gray-700 dark:bg-gray-900 dark:text-gray-300">Back</button>
<button type="button" data-modal-next class="rounded-lg bg-blue-600 px-4 py-2 text-sm font-semibold text-white hover:bg-blue-700 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-600 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-blue-400 dark:focus-visible:ring-offset-gray-900">Next</button>
</div>
</div>
</div>| Prop | Type | Default | Description |
|---|---|---|---|
openrequired | boolean | - | Whether the component is currently shown. |
stepsrequired | Step[] | - | The ordered steps of the process. |
onFinishrequired | () => void | - | On finish |
onDismissrequired | () => void | - | Fired when the user dismisses the notification. |
The step count lives in state: Back is disabled on the first step and the primary button becomes Finish on the last. The step region is `aria-live` so each change is announced, and progress is not colour-only - the active dot is wider, and the current step is spelled out as "Step 2 of 3". The dialog keeps its focus trap and Escape throughout, and the guarded `steps[index]` access tolerates an empty array.