Component

Action Toast

Toast with an inline action button (Undo). Fires an onAction callback when the action button is clicked, otherwise auto-dismisses after 6 seconds. Ideal for reversible destructive actions like delete.

  • Component
  • Tailwind
  • HTML
  • MIT

What it does

Capabilities

  • Inline action button
  • OnAction callback
  • 6s auto-dismiss
  • Pause on hover
  • Close button
  • Role status
  • Aria-live polite

Preview

Live component

Interactive preview
Open preview
9:41 100%
devsnips.site/library/tailwind/components/toasts/action-toast/
fluid · no fixed width 100%
No dependencies Focus-visible

Install

Add to your project

terminal
npx devsnips add Tailwind/Components/Toasts/action-toast
registry path: Tailwind/Components/Toasts/action-toast

Source

Implementation

code.html
<!--
Snippet Name: Action Toast
Description: Toast with an inline action button (Undo). Fires a callback on action, or auto-dismisses if ignored.
Author: DevSnips Contributors
Usage Example: Call showToast({ action: 'Undo', onAction: () => revert() }) after destructive actions.
-->
<div
  id="action-toast-region"
  class="pointer-events-none fixed bottom-4 right-4 z-50 flex w-full max-w-sm flex-col items-end gap-3"
  role="region"
  aria-label="Notifications"
  aria-live="polite"
  data-toast-region
></div>

<!-- Demo trigger buttons -->
<div class="flex flex-wrap gap-2">
  <button onclick="showToast()" class="inline-flex items-center gap-2 rounded-xl bg-gray-900 px-5 py-2.5 text-sm font-semibold text-white hover:bg-gray-800 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-500 focus-visible:ring-offset-2">
    <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6M1 7h22M9 7V4a1 1 0 011-1h4a1 1 0 011 1v3"/></svg>
    Delete item
  </button>
</div>

<script>
  (function () {
    const root = document.currentScript.closest('[data-toast-region]');
    if (!root) return;

    function dismiss(toast) {
      if (!toast || toast.dataset.dismissed === 'true') return;
      toast.dataset.dismissed = 'true';
      toast.classList.add('translate-x-2', 'opacity-0');
      toast.addEventListener('transitionend', () => toast.remove(), { once: true });
      setTimeout(() => toast.remove(), 400);
    }

    function showToast(opts) {
      opts = opts || {};
      const actionLabel = opts.action || 'Undo';
      const onAction = typeof opts.onAction === 'function' ? opts.onAction : function () {};
      const duration = opts.duration || 6000;

      const toast = document.createElement('div');
      toast.className = 'toast-item pointer-events-auto flex w-full items-start gap-3 rounded-xl border border-gray-200 bg-white p-4 shadow-lg ring-1 ring-black/5 transition duration-300 ease-out';
      toast.setAttribute('role', 'status');
      toast.innerHTML = `
        <span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-gray-900 text-white">
          <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6M1 7h22M9 7V4a1 1 0 011-1h4a1 1 0 011 1v3"/></svg>
        </span>
        <div class="min-w-0 flex-1">
          <p class="text-sm font-semibold text-gray-900">1 item deleted</p>
          <p class="mt-0.5 text-sm text-gray-500">Removed from your workspace.</p>
        </div>
        <div class="flex shrink-0 items-center gap-2">
          <button type="button" class="toast-action rounded-md px-2.5 py-1 text-sm font-semibold text-blue-600 transition-colors hover:bg-blue-50 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500">${actionLabel}</button>
          <button type="button" class="toast-close rounded-md p-1 text-gray-400 transition-colors hover:bg-gray-100 hover:text-gray-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-gray-400" aria-label="Dismiss notification">
            <svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/></svg>
          </button>
        </div>`;

      root.appendChild(toast);

      function close() { clearTimeout(timer); dismiss(toast); }

      const timer = setTimeout(() => dismiss(toast), duration);
      toast.querySelector('.toast-close').addEventListener('click', close);
      toast.querySelector('.toast-action').addEventListener('click', () => { onAction(); close(); });
      toast.addEventListener('mouseenter', () => clearTimeout(timer));
    }

    window.showToast = showToast;
  })();
</script>
73 lines UTF-8 · LF · Spaces: 2
DevSnips AI ready Claude · Cursor · Windsurf

Agent skill & Model Context Protocol

Pass this component straight into your AI workflow. DevSnips exposes each resource as a structured, addressable registry entry, so your agent installs the real files instead of approximating them.

devsnips://components/toasts/action-toast
Prompt instruction
I want to use this DevSnips resource in production:

Page:
https://devsnips.site/library/tailwind/components/toasts/action-toast/

Install: npx devsnips add
Tailwind/Components/Toasts/action-toast

This is the Action Toast — Toast with an inline action button (Undo). Fires an onAction callback when the action button is clicked, otherwise auto-dismisses after 6 seconds. Ideal for reversible destructive actions like delete.

Use this DevSnips resource as the starting point for my project.
Adapt it to my project's stack and conventions, fix any issues,
and make it production-ready while preserving its intended design
and behavior.

Paste into ChatGPT, Claude or your agent — it already carries the page URL and the exact install path.

Resource URI
devsnips://components/toasts/action-toast