Search documentation

Find a component or a docs page

Toast

An opinionated toast component.

Examples

Types

Click any to spawn a toast.

About

Trigger toasts from the server with Turbo Streams or from JavaScript via window.RubyUI.toast.*. Mirrors shadcn's Toast (Base UI): a polite live region, toasts that stack, pause while hovered or focused, and swipe away. Press F6 to move focus to the notifications, Tab to reach the newest toast and Escape to dismiss it.

Mount

# In application_layout.rb (Phlex), once globally:
render RubyUI::ToastRegion.new

# Pass flash to render Rails flash on initial load:
render RubyUI::ToastRegion.new(flash: helpers.flash.to_h)

# The region is a popover="manual": a toast fired while a modal
# Dialog/Sheet is open shows above it (it becomes clickable once
# the modal closes, since the page behind a modal is inert).

Position

Use the position prop to change where toasts mount.

Server-pushed (Turbo Stream)

Append a toast to the global region from any controller.

# Option A — custom Turbo Stream action (compact):
render turbo_stream: turbo_stream.action(
  :toast,
  target: "ruby-ui-toaster",
  variant: :success,
  title: "Saved",
  description: "Project updated."
)

# Option B — append a fully-rendered ToastItem (for Action / Cancel slots):
render turbo_stream: turbo_stream.append("ruby-ui-toaster") {
  render RubyUI::ToastItem.new(variant: :success) do
    render RubyUI::ToastIcon.new(variant: :success)
    div(class: "flex min-w-0 flex-1 flex-col gap-1") do
      render RubyUI::ToastTitle.new { "Saved" }
      render RubyUI::ToastDescription.new { "Project updated." }
    end
    render RubyUI::ToastAction.new(label: "Undo", on: "click->projects#undo")
    render RubyUI::ToastClose.new
  end
}

JavaScript API

Hotwire-friendly: window.RubyUI.toast.* is sugar over a CustomEvent dispatch. Either path works.

// Sugar:
RubyUI.toast.success("Saved", { description: "Project updated." })
RubyUI.toast.error("Boom")
RubyUI.toast.info("Heads up")
RubyUI.toast.warning("Storage almost full")
RubyUI.toast.loading("Working...")
RubyUI.toast("Saved", { priority: "high" }) // announced right away
RubyUI.toast.dismiss(id)              // no-arg: dismiss all (alias: close)
RubyUI.toast.promise(p, { loading, success, error })

// Equivalent CustomEvent (any source can dispatch this):
window.dispatchEvent(new CustomEvent("ruby-ui:toast", {
  detail: { variant: "success", title: "Saved", description: "..." }
}))

Installation

Components

ComponentBuilt usingSource
ToastPhlex
ToastActionPhlex
ToastCancelPhlex
ToastClosePhlex
ToastDescriptionPhlex
ToastDocsPhlex
ToastIconPhlex
ToastItemPhlex
ToastRegionPhlex
ToastTitlePhlex
ToastControllerStimulus JS
ToasterControllerStimulus JS

API Reference

ToastRegion (Toaster)

PropDefaultValuesDescription
position:bottom_right:top_left | :top_center | :top_right | :bottom_left | :bottom_center | :bottom_rightWhere the toaster mounts on the viewport (shadcn's is bottom-right).
expandfalseBooleanAlways show toasts expanded (no stack peek).
max3IntegerToasts shown at once (Base UI limit). Older ones stay hidden and come back when a front toast closes.
duration5000Integer (ms) | Float::INFINITYDefault lifetime per toast (Base UI timeout). 0 or Float::INFINITY keeps toasts until dismissed.
gap12Integer (px)Spacing between toasts when expanded.
close_buttontrueBooleanRender the X button in every toast.
hotkey%w[F6]Array<String>Shortcut that moves focus to the notifications region (Tab then reaches the newest toast), e.g. %w[alt t].
swipe_directions(from position)Array<:up | :down | :left | :right>Directions a swipe can dismiss in. Defaults to down/right for bottom-right; [] disables swipe.
flashnilHash | nilPass `helpers.flash.to_h` to render Rails flash on initial load.

ToastItem

PropDefaultValuesDescription
variant:default:default | :success | :error | :warning | :info | :loadingIcon and data-type.
priority:low:low | :highHigh-priority toasts are announced right away (role=alert) and use role=alertdialog.
idnilStringDOM id; auto-generated when not provided.
durationnilInteger | Float::INFINITY | nilOverride the region default. nil inherits it; 0 or Float::INFINITY stays until dismissed.
dismissibletrueBooleanAllow Escape, swipe, the X and Cancel to close it. RubyUI.toast.dismiss() closes it either way.
on_dismissnilStringStimulus action ("controller#method") run on ruby-ui:toast:close. The controller must be on the toast or an ancestor.
on_removenilStringStimulus action run on ruby-ui:toast:remove, after the exit animation.

JS API options

Second argument to RubyUI.toast.<variant>(message, options) or ruby-ui:toast CustomEvent detail.

PropDefaultValuesDescription
title—StringHeadline text. Falls back to the first positional argument.
description—StringSecondary line under the title.
duration(region default)Number | Infinityms before auto-dismiss. 0 or Infinity = stays until dismissed.
priority"low""low" | "high""high" is announced right away.
action—{ label, onClick }Action button (outline). Clicking it closes the toast.
cancel—{ label, onClick }Secondary dismiss button (RubyUI extra).
closeButton(region default)BooleanShow or hide the X on this toast.
onClose—FunctionCalled when the toast starts closing ({ id, reason }).
onRemove—FunctionCalled after the exit animation, when the toast leaves the DOM.
swipeDirections(region default)Array<String>Directions a swipe can dismiss this toast in.
position(region default)StringMoves the region before this toast is added.
id(auto)StringStable id (used by .dismiss(id) and .promise).
dismissibletrueBooleanfalse turns off Escape, swipe, the X and Cancel for this toast; RubyUI.toast.dismiss() still closes it.
className—StringExtra classes on the toast element.