Toast
A succinct message that is displayed temporarily.
Installation
Add the component to your project:
rails generate shadcn:component toast
Usage
Toasts are typically triggered by user actions and rendered dynamically.
The ToastViewportComponent
provides a container positioned at the bottom-right of the screen (or top on mobile).
<%= render Shadcn::ToastViewportComponent.new do %>
<%= render Shadcn::ToastComponent.new do |toast| %>
<% toast.with_title { "Scheduled" } %>
<% toast.with_description { "Your message has been scheduled." } %>
<% end %>
<% end %>
Examples
Simple
A minimal toast with just a description.
<%= render Shadcn::ToastComponent.new do |toast| %>
<% toast.with_description { "Your message has been sent." } %>
<% end %>
With Title
Include both a title and description for more context.
<%= render Shadcn::ToastComponent.new do |toast| %>
<% toast.with_title { "Scheduled: Catch up" } %>
<% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
<% end %>
With Action
Add an action button to allow users to respond to the notification.
The alt_text parameter
is required for accessibility.
<%= render Shadcn::ToastComponent.new do |toast| %>
<% toast.with_title { "Scheduled" } %>
<% toast.with_description { "Your message has been scheduled." } %>
<% toast.with_action(alt_text: "Undo") do %>
Undo
<% end %>
<% end %>
Destructive
Use the destructive variant for error messages or critical notifications.
<%= render Shadcn::ToastComponent.new(variant: :destructive) do |toast| %>
<% toast.with_title { "Uh oh! Something went wrong." } %>
<% toast.with_description { "There was a problem with your request." } %>
<% toast.with_action(alt_text: "Try again") do %>
Try again
<% end %>
<% end %>
Custom Duration
Control how long the toast is displayed before auto-dismissing. Duration is specified in milliseconds.
<%= render Shadcn::ToastComponent.new(duration: 3000) do |toast| %>
<% toast.with_description { "This will close in 3 seconds." } %>
<% end %>
No Auto-dismiss
Set duration: 0
to prevent automatic dismissal. The user must manually close the toast.
<%= render Shadcn::ToastComponent.new(duration: 0) do |toast| %>
<% toast.with_title { "Important" } %>
<% toast.with_description { "This toast will stay until manually dismissed." } %>
<% end %>
API Reference
ToastComponent
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| variant |
Symbol
|
:default
|
Toast style variant (:default, :destructive) |
| duration |
Integer
|
5000
|
Auto-dismiss duration in milliseconds (0 for no auto-dismiss) |
| open |
Boolean
|
true
|
Whether the toast is visible |
| class_name |
String
|
nil
|
Additional CSS classes to apply |
ToastComponent Slots
| Slot | Props | Description |
|---|---|---|
| with_title | - | Toast title (bold heading) |
| with_description | - | Toast description text |
| with_action | alt_text: (required) |
Action button (requires alt_text for accessibility) |
| with_close | - | Custom close button (default provided) |
ToastViewportComponent
Container component for toasts, positioned at bottom-right on desktop and top on mobile.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
| class_name |
String
|
nil
|
Additional CSS classes to apply |
Stimulus Controller
The Toast component uses a Stimulus controller (shadcn--toast)
for auto-dismiss functionality and close button interaction.
Values
| Value | Type | Default | Description |
|---|---|---|---|
| duration | Number | 5000 | Auto-dismiss time in milliseconds |
| open | Boolean | true | Whether toast is visible |
Actions
| Action | Description |
|---|---|
| close | Manually close the toast |
| pause | Pause auto-dismiss timer (useful on hover) |
| resume | Resume auto-dismiss timer |
Events
| Event | Description |
|---|---|
| shadcn--toast:closed | Dispatched when toast is closed and removed from DOM |
Integration Example
Here's an example of dynamically adding toasts using Turbo Streams or JavaScript:
// Add a toast dynamically
function addToast(title, description, variant = 'default') {
const viewport = document.querySelector('[data-shadcn--toaster-target="viewport"]');
const toast = document.createElement('li');
toast.setAttribute('data-controller', 'shadcn--toast');
toast.setAttribute('data-shadcn--toast-duration-value', '5000');
toast.setAttribute('data-shadcn--toast-open-value', 'true');
toast.setAttribute('data-state', 'open');
toast.setAttribute('role', 'status');
toast.setAttribute('aria-live', 'polite');
const variantClasses = variant === 'destructive'
? 'destructive group border-destructive bg-destructive text-destructive-foreground'
: 'border bg-background text-foreground';
toast.className = `group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all ${variantClasses}`;
toast.innerHTML = `
<div class="grid gap-1">
${title ? `<div class="text-sm font-semibold [&+div]:text-xs">${title}</div>` : ''}
<div class="text-sm opacity-90">${description}</div>
</div>
<button type="button" class="absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100" data-action="click->shadcn--toast#close" aria-label="Close">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" class="h-4 w-4">
<path d="M18 6 6 18M6 6l12 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
`;
viewport.appendChild(toast);
}
Accessibility
- Uses
role="status"for proper screen reader announcement - Has
aria-live="polite"to announce changes without interrupting - Close button has
aria-label="Close"for screen readers - Action buttons require
alt_textparameter foraria-label - Auto-dismiss timer can be paused on hover for users who need more time to read
- All interactive elements are keyboard accessible
- Color is not the only indicator - text content provides meaning
On This Page