Toast
A brief, auto-dismissing notification message.
Installation
Included in poetry-ui — available as
poetry_toast
the moment you've installed Poetry,
with no per-component step. To own the source and edit it, copy it into your app:
bin/rails g poetry:add toast
Default
-
Event scheduledFriday, July 10 at 5:00 PM
<%# duration: 0 pins the toast open for this demo - without it a plain
toast auto-dismisses after 5s (the timer pauses on hover and focus). %>
<ul class="w-full max-w-sm">
<%= poetry_toast(duration: 0) do |toast| %>
<% toast.with_title { "Event scheduled" } %>
<% toast.with_description { "Friday, July 10 at 5:00 PM" } %>
<% end %>
</ul>
Promise
<%# Upstream toast-promise, the Rails way: the job appends a LOADING
toast (persistent by contract), then REPLACES it in place - same
toast id - with the settled result. In a real app both steps are
Turbo Streams (turbo_stream.poetry_toast to append, then
turbo_stream.replace from the job); the demo-toast controller
stands in for the job with a 2s timer. %>
<div data-controller="demo-toast" class="flex w-full flex-col items-start gap-3">
<%= poetry_button(variant: :outline, "data-action": "demo-toast#create") { "Create Event" } %>
<div class="h-40 w-full overflow-hidden rounded-lg border contain-content">
<%= poetry_toaster(id: "promise-toaster", "data-demo-toast-target": "toaster") %>
</div>
<template data-demo-toast-target="loading">
<%= poetry_toast(variant: :loading, id: "promise-toast") do |toast| %>
<% toast.with_title { "Creating event…" } %>
<% end %>
</template>
<template data-demo-toast-target="settled">
<%= poetry_toast(variant: :success, id: "promise-toast", duration: 0) do |toast| %>
<% toast.with_title { "Event created." } %>
<% end %>
</template>
</div>
Variants
-
Changes savedYour profile has been updated.
-
Heads upA new version is available.
-
Storage almost fullYou have used 90% of your quota.
-
Creating event…Persistent until the job replaces it.
-
Payment failedYour card was declined.
<%# Each variant brings its own icon; destructive also announces
assertively (politeness derives from the variant). %>
<ul class="flex w-full max-w-sm flex-col gap-2">
<%= poetry_toast(variant: :success, duration: 0) do |toast| %>
<% toast.with_title { "Changes saved" } %>
<% toast.with_description { "Your profile has been updated." } %>
<% end %>
<%= poetry_toast(variant: :info, duration: 0) do |toast| %>
<% toast.with_title { "Heads up" } %>
<% toast.with_description { "A new version is available." } %>
<% end %>
<%= poetry_toast(variant: :warning, duration: 0) do |toast| %>
<% toast.with_title { "Storage almost full" } %>
<% toast.with_description { "You have used 90% of your quota." } %>
<% end %>
<%= poetry_toast(variant: :loading, duration: 0) do |toast| %>
<% toast.with_title { "Creating event…" } %>
<% toast.with_description { "Persistent until the job replaces it." } %>
<% end %>
<%= poetry_toast(variant: :destructive, duration: 0) do |toast| %>
<% toast.with_title { "Payment failed" } %>
<% toast.with_description { "Your card was declined." } %>
<% end %>
</ul>
With action
-
Message deleted
<%# An action-bearing toast defaults to persistent (a missable undo is a
bug) - no duration needed. Clicking the action dismisses the toast. %>
<ul class="w-full max-w-sm">
<%= poetry_toast do |toast| %>
<% toast.with_title { "Message deleted" } %>
<% toast.with_action { "Undo" } %>
<% end %>
</ul>
API
Poetry::Ui::Toast::Component — options are
constructor keywords (the poetry_* helper forwards them);
slots are composed inside the block. Generated from the gem's source documentation.
| Option | Type | Details | Description |
|---|---|---|---|
| variant: | Symbol | one of: default, success, info, warning, destructive, loading; defaults to :default |
The intent axis: it picks the icon, and :destructive announces assertively while :loading defaults to persistent. |
| duration: | Integer | nil = derived: 5000ms, or PERSISTENT when an action slot is present (the missable-undo guard). <= 0 = persistent. | |
| politeness: | Symbol | one of: polite, assertive; defaults to -> { variant == :destructive ? :assertive : :polite } |
Derived from the variant: destructive announces assertively. |
| show_close_button: | Boolean | defaults to true |
The corner dismiss button - named as the dialog family names it. |
Slots
| Writer | Description |
|---|---|
| with_action | Typed Button slot (undo / view / retry): clicking it dismisses the toast with reason \"action\". Its presence makes the toast persistent by default. |
| with_description | Supporting copy under the title. |
| with_title | The message (REQUIRED - the announced payload's first line). |
Styling
Every part carries a stable data-slot attribute — target
[data-slot=…] from your own CSS to restyle it. State rides
data attributes on the parts below. This contract is verified against rendered DOM in CI.
| Part | Description |
|---|---|
| [data-slot=toast] | The notification item itself (<li>, role=status) - variant, open state, and the toaster's stack facts all ride here |
| [data-slot=toast-icon] | The variant's icon well (aria-hidden; the default variant renders none) |
| [data-slot=toast-title] | The message - the announced payload's first line (required slot) |
| [data-slot=toast-description] | Supporting copy under the title |
State attributes
| Part | Attribute | Condition | Values |
|---|---|---|---|
| toast | data-open | toast is showing (the server-rendered state; the dismiss exit flips the pair before removal) | — |
| toast | data-closed | toast is animating out | — |
| toast | data-variant | always - the resolved variant | default · success · info · warning · destructive · loading |
| toast | data-queued | the toaster holds it hidden past the visible limit (timer paused until a slot frees up) | — |
CSS variables
| Part | Variable | Description |
|---|---|---|
| toast | --poetry-toast-index | stack position written by the toaster's reflow (newest visible toast = 0) |
Wiring
The Stimulus surface each element carries — declared in the component, verified against rendered DOM in CI. Bare actions fire on the element's default event.
| Element | Controller | Wiring |
|---|---|---|
| root | poetry--core--toast | registers · value duration · value politeness · pause on mouseenter/focusin · resume on mouseleave/focusout |
| action | poetry--core--toast | dismiss on click · target action |
| close | poetry--core--toast | dismiss on click · target close |