Modals
Modal dialogs built on the native <dialog> element, with a trigger button, header, scrollable body, and backdrop-click to close. Wired up to the l-ui--modal Stimulus controller.
CSS-classes example
Use the l-ui-modal classes directly when you need full control over markup.
Helper
The l_ui_modal helper renders the trigger, dialog, header (with title and close button), and Stimulus wiring for you. The block's content is the modal body. Use <% (not <%=) when calling m.trigger - the builder captures its content.
Opening from elsewhere
Give the modal a known id: and add data-l-ui-modal-open="<that id>" to any button on the page. The button does not need to be inside the helper's wrapper, and no data-controller or data-action is required - the l-ui--modal controller listens at the document level for matching clicks.
Calling dialog.showModal() directly is not supported - it bypasses the l-ui--modal controller and skips scroll lock, focus restoration, open-count tracking, and the screen-reader announcement.
Helper options
| Option | Description |
|---|---|
title: |
Required. Heading text; also used for aria-labelledby |
id: |
DOM id for the <dialog>; defaults to an auto-generated id |
heading_level: |
Heading tag for the title (e.g. :h2, :h3); defaults to :h3 |
container: |
Extra HTML attributes for the wrapping <div> (e.g. class:) |
m.trigger(**opts) |
Optional. Renders a colocated trigger <button>; opts are merged as HTML attributes. For additional or external triggers, add data-l-ui-modal-open="<id>" to any button |
| block content | The block's output (anything outside m.trigger) is rendered inside the scrollable l-ui-modal__body |
| icon-only triggers | If the trigger contains only an icon (no visible text), pass aria-label: so it has an accessible name |
CSS classes
| Class | Description |
|---|---|
l-ui-modal |
Applied to the <dialog>; fullscreen on mobile, centred and capped on desktop |
l-ui-modal__header |
Top bar containing the title and close button |
l-ui-modal__body |
Scrollable body region; fills the remaining dialog height |