Plan step 22, actions.md § Missing (two-line snackbar height, snackbar
keyboard shortcut): the container grew organically from `min-h-12` rather
than sitting at SnackbarTokens.TwoLinesContainerHeight, and there was no
way for a keyboard to reach an actioned snackbar at all.
A `description` is M3's second line, so the snackbar is pinned to 68px
whenever one is there, and below `medium` a two-line snackbar with an
action wraps the action under the text — M3's "two lines with longer
action" configuration. Alt+G, the shortcut M3 suggests for the web, moves
the focus to a snackbar that carries an action from wherever the page had
it; `event.code`, because Alt rewrites `event.key` on some layouts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
M3 says to avoid an icon in a snackbar and gives the supporting text no fourth
colour, so the state glyph and the 80% description are gone: a type now only
picks the announcement role. The 40px action and close buttons take the shared
touch-target, Escape dismisses a snackbar that holds the focus, and the host
publishes --material-snackbar-height on <html> so a `fab` button sits above the
snackbar instead of under it. Plan step 18, actions.md ACT-17, ACT-18, ACT-20,
ACT-34, ACT-35.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
The region carrying aria-live was created together with its message, inside the
x-if that draws the snackbar, so a screen reader had nothing to notice changing.
It moves to the permanent host, which is polite and atomic as M3 asks; a type
now only picks the region's role, and the explicit aria-live keeps an error
polite too. Plan step 11, actions.md ACT-02.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Qwx5USif3wFFmxtHg5U1g9
A sticky toast stays until it is dismissed or its action pressed, for a
question that must be answered ("A new version is ready" with Reload).
It is kept aside rather than queued, so it never holds up ordinary
toasts: one that arrives while it shows takes its place, and the sticky
toast comes back once the queue is empty. One is kept at a time; a newer
sticky toast replaces it. Every other toast keeps today's queue.
An action's `event` names a window event dispatched when it is pressed,
beside `handler`, for toasts whose detail cannot carry a function. The
snackbar now closes before either runs, so a toast they show is not the
one dismissed.
`data-toast` and `data-toast-action` give applications stable hooks for
their tests.
The queue now forgets a cleared timer in next(): a toast dismissed by a
click that neither hovered nor focused it first, as a screen reader
activates a button, left its timer running and cut the next toast short.
The showcase's snackbar buttons had no Alpine scope and did nothing; they
are wrapped in one, with a sticky example.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RHoXZSHc8gGpZjFmA5fPc2
<x-toast> hosts the snackbar queue for the Toasts concern and
window.materialToast(), one at a time, paused on hover and focus, with
an optional action; it listens from the moment its script loads, so a
toast dispatched before Alpine starts is shown rather than lost.
<x-badge> is M3's dot and count, plus a tonal or outlined status label;
<x-rich-tooltip> is transient or persistent; <x-alert>, <x-stat> and
<x-empty-state> are built from M3's parts.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01V9NnLxnPp8vaaurb3Z1MFy