Alert

v0.0.10

v0.0.10StableHeadlessStatelessAccessibleJS-moduleApache-2.0
Installation mix mishka.ui.gen.headless alert
Source View Source

Overview of the Phoenix and LiveView Headless Alert Component

The Mishka Chelekom Headless Alert is an unstyled Phoenix function component for a message the user did not ask for, such as a saved draft or a failed request. It renders one div with live region semantics and splits the message into parts: icon, title, content, actions and close. Each part has a data-part attribute and a *_class attribute, so every color, border and space comes from your own Tailwind classes.

Urgency decides how the alert is announced. The default, polite, renders role="status" with aria-live="polite", so a screen reader finishes its sentence first. assertive renders role="alert", which interrupts. off renders a plain region for a message that was already on the page at load. A title slot is linked to the root with aria-labelledby, so the heading is read before the body. With dismissible, the close button hides the alert in the browser using Phoenix LiveView JS commands, with no hook and no round trip.

Base UI Alert example - dismissible alert with a title (Phoenix headless)

Base UI Alert example - dismissible alert with a title (Phoenix headless)

Draft saved Your changes are stored locally until you publish.
heex
<.alert
  id="baseui-alert-hero"
  dismissible
  class="flex w-full max-w-96 items-start gap-3 rounded-md border border-neutral-200 bg-white p-3 text-sm text-neutral-950 dark:border-neutral-800 dark:bg-neutral-950 dark:text-white"
  title_class="block font-medium"
  content_class="flex-1"
  close_class="rounded-sm text-neutral-500 hover:text-neutral-950 dark:hover:text-white focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-neutral-950 dark:focus-visible:outline-white"
>
  <:title>Draft saved</:title>
  Your changes are stored locally until you publish.
</.alert>

Base UI Alert example - polite and assertive urgency (Phoenix headless)

Base UI Alert example - polite and assertive urgency (Phoenix headless)

Saved a moment ago.
heex
<div class="flex w-full max-w-96 flex-col gap-2">
  <.alert
    id="baseui-alert-polite"
    urgency="polite"
    class="rounded-md border border-neutral-200 bg-white p-3 text-sm text-neutral-950 dark:border-neutral-800 dark:bg-neutral-950 dark:text-white"
  >
    Saved a moment ago.
  </.alert>
  <.alert
    id="baseui-alert-assertive"
    urgency="assertive"
    class="rounded-md border border-red-600 bg-white p-3 text-sm text-red-700 dark:border-red-500 dark:bg-neutral-950 dark:text-red-400"
  >
    Could not reach the server.
  </.alert>
</div>

Dismissing an alert

dismissible adds a close button. It is a button with type="button" and an aria-label taken from close_label, which defaults to Dismiss. The glyph is ✕ unless you fill the close_icon slot. By default the button hides the alert with Phoenix.LiveView.JS.hide/1, aimed at the alert's own id. That is why id is required and has to be unique.

on_dismiss changes what the button does. Pass a %Phoenix.LiveView.JS{} to replace the default command, or a string to push that LiveView event instead. Use the event when the server has to forget the message, then stop rendering the alert in your template. The event is pushed without a payload.

heex
<.alert :if={@saved?} id="draft-saved" dismissible on_dismiss="forget_saved">
  <:title>Draft saved</:title>
  Your changes are stored locally until you publish.
</.alert>
elixir
def handle_event("forget_saved", _params, socket) do
  {:noreply, assign(socket, :saved?, false)}
end

Icon and actions

The icon slot renders before the message inside a span marked aria-hidden, so keep it to decoration. The actions slot renders after the message and holds buttons or links. Style them with icon_class and actions_class. The title goes in the title slot and is styled with title_class.

Parts & data attributes

The root carries data-urgency, and data-dismissible when the alert can be dismissed. The parts are marked data-part="icon", data-part="content", data-part="title", data-part="actions" and data-part="close". The title sits inside the content part, before the message. Every element also has a structural class such as chelekom-alert__content that you can target from your own CSS. Extra attributes you pass, such as data-* or aria-*, land on the root.

Accessibility

Follows the WAI-ARIA Alert pattern. Polite alerts use role="status" and assertive ones use role="alert". The title names the region through aria-labelledby, and the icon is hidden from assistive technology. The close button is a native button, so Enter and Space dismiss the alert.