Toast

Low-level toast markup kept for compatibility.

Back-compat Stimulus Controller
  • Scheduled: Catch up
    Friday, February 10, 2023 at 5:57 PM
  • toast/default
    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Scheduled: Catch up" } %>
      <% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
    <% end %>
    

    Installation

    For new toast work, install Sonner. Install Toast only when you need the lower-level compatibility component.

    Add the component to your project:

    rails generate shadcn:add toast

    Usage

    Toast renders individual notification markup and is kept for apps that already depend on it. New code should use Sonner, which provides the recommended toast() API, stacking, positions, swipe dismissal, and Turbo Stream support.

    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Scheduled: Catch up" } %>
      <% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
    <% end %>
    

    Examples

    Simple

    A minimal toast with just a description.

    With Title

    Include both a title and description for more context.

    With Action

    Add an action button to allow users to respond to the notification. The alt_text parameter is required for accessibility.

    Destructive

    Use the destructive variant for error messages or critical notifications.

    Custom Duration

    Control how long the toast is displayed before auto-dismissing. Duration is specified in milliseconds.

    No Auto-dismiss

    Set duration: 0 to prevent automatic dismissal. The user must manually close the toast.

    All Variants

  • Success
    Your changes have been saved.
  • toast/variants
    <div class="space-y-3">
      <%= render Shadcn::Toast.new do |toast| %>
        <% toast.with_title { "Success" } %>
        <% toast.with_description { "Your changes have been saved." } %>
      <% end %>
    
      <%= render Shadcn::Toast.new(variant: :destructive) do |toast| %>
        <% toast.with_title { "Error" } %>
        <% toast.with_description { "Something went wrong." } %>
      <% end %>
    </div>
    

    With Description

  • Scheduled: Catch up
    Friday, February 10, 2023 at 5:57 PM
  • toast/with_description
    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Scheduled: Catch up" } %>
      <% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
    <% end %>
    

    Destructive with Action

  • Uh oh! Something went wrong.
    There was a problem with your request.
  • toast/destructive_with_action
    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Scheduled: Catch up" } %>
      <% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
    <% end %>
    

    Success

  • Success!
    Your changes have been saved successfully.
  • toast/success
    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Success!" } %>
      <% toast.with_description { "Your changes have been saved successfully." } %>
    <% end %>
    

    Warning

  • Warning
    Your session will expire in 5 minutes.
  • toast/warning
    <%= render Shadcn::Toast.new do |toast| %>
      <% toast.with_title { "Warning" } %>
      <% toast.with_description { "Your session will expire soon." } %>
      <% toast.with_action(alt_text: "Extend session") do %>
        <%= render Shadcn::Button.new(variant: :outline, class_name: "h-8 px-3 text-xs") { "Extend" } %>
      <% end %>
    <% end %>
    

    Long Duration

  • Important message
    This toast will stay visible for 10 seconds.
  • toast/long_duration
    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Scheduled: Catch up" } %>
      <% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
    <% end %>
    

    No Auto Dismiss

  • Manual dismiss required
    This toast will not auto-dismiss. Click the X to close.
  • toast/no_auto_dismiss
    <%= render(Shadcn::ToastComponent.new(duration: 0)) do |toast| %>
      <% toast.with_title { "Manual dismiss required" } %>
      <% toast.with_description { "This toast will not auto-dismiss. Click the X to close." } %>
    <% end %>
    

    Multiple Toasts

  • Multiple Toasts Example
    In a real app, multiple toasts stack in the ToastViewport container. See docs for integration guide.
  • toast/multiple
    <%= render(Shadcn::ToastComponent.new) do |toast| %>
      <% toast.with_title { "Scheduled: Catch up" } %>
      <% toast.with_description { "Friday, February 10, 2023 at 5:57 PM" } %>
    <% end %>
    

    API Reference

    ToastComponent

    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.

    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_text parameter for aria-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