mica
mica

Example

Confirm

This is a description.

Body content sits between header and footer.

Drawer

The same native dialog dressed as a drawer.

Body content; the footer pins to the bottom with stacked actions.

Form drawer

On mobile, open the keyboard and move between fields. The body scrolls while the footer stays available.

Project details

Basic usage

<button commandfor="confirm" command="show-modal">Open</button>  <!-- trigger -->

<dialog id="confirm">          <!-- content -->
  <button class="close" commandfor="confirm" command="close" aria-label="Close">&#x2715;</button>
  <header>                     <!-- header -->
    <h2>Are you sure?</h2>     <!-- title -->
    <p>This cannot be undone.</p>  <!-- description -->
  </header>

  <p>Any body content.</p>

  <footer>                     <!-- footer: right-aligned row -->
    <form method="dialog">
      <button>Cancel</button>
      <button data-variant="primary" value="ok">Confirm</button>
    </form>
  </footer>
</dialog>

API

Attributes

NameTypeDefaultDescription
data-avoid-keyboardfalseautomaticOn a drawer, disables the optional module’s keyboard positioning when your application manages it.
data-drawerbooleanfalseTurns the dialog into a responsive desktop side sheet and mobile bottom sheet.
opennative booleanfalseReflects whether the native dialog is open. Prefer showModal() to open a modal.

Content/markup contract

PartContractDefaultDescription
headerdirect childoptionalContains the title and description.
Bodyone element between header and footerPadded, scrollable content region.
footerdirect childoptionalRight-aligned actions; drawer actions stack and pin to the bottom. A form method="dialog" closes natively.
button.closedirect childoptionalCorner dismiss control; provide an accessible name.

Native methods and values

NameTypeDefaultDescription
showModal()methodOpens in the top layer with modal focus and backdrop behavior.
close()methodCloses the dialog.
returnValuestring property""Carries the value of the button that submitted a method="dialog" form.

drawer.js

Optional. Below 40rem the drawer is a content-height, full-width bottom sheet. The module adds a grab handle and swipe-to-dismiss from the handle/header strip: downward drags follow the pointer, upward drags resist, and the sheet closes past one third of its height or on a flick. It also manages the mobile scrim, lightening it during drag and fading it on close, including on iOS. Without the module, open/close, Esc, and the CSS-only scrim still work; no handle appears.

<script type="module" src="mica/drawer.js"></script>

While editing in a mobile drawer, the module fits the sheet above the software keyboard, keeps its body scrollable, and reveals the focused field. It restores authored positioning when the keyboard closes and leaves pinch zoom to the browser. Use data-avoid-keyboard="false" if your application already manages keyboard positioning. This requires the browser’s Visual Viewport API; without it, native behavior remains.

On mobile the handle is the dismiss affordance, so you may hide the redundant corner close button:

@media (max-width: 40rem) {
  dialog[data-drawer] > button.close { display: none; }
}

invoker.js

Temporary optional shim for the recipe's show-modal and close invoker commands. It installs nothing when commands are native.

<script type="module" src="mica/invoker.js"></script>

Accessibility

Native modal dialogs provide top-layer behavior, focus trapping, Esc dismissal, and backdrop handling. Give icon-only close buttons an accessible name. Use a heading and description in the header so the purpose is clear.

Browser support

Invoker commands (commandfor/command) are Baseline newly-available (Chrome 135+, Firefox 144+, Safari 26.2+). Include invoker.js until they are widely available. The shim's removal is a one-line diff.

Notes

Enter/exit animations use @starting-style and transition-behavior: allow-discrete. Standard modal backdrops fade where the engine supports top-layer exit transitions.

← stepperaccordion →