Component

Status Toasts

Four semantic toast variants — success, error, warning, info — each with a matching icon, accent color, and ARIA role. Errors and warnings use role=alert; success and info use role=status.

  • Component
  • Tailwind
  • HTML
  • MIT

Preview

Live component

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

Install

Add to your project

terminal
npx devsnips add Tailwind/Components/Toasts/status-toasts
registry path: Tailwind/Components/Toasts/status-toasts

Source

Implementation

code.html
<!--
Snippet Name: Status Toasts
Description: Four semantic toast variants — success, error, warning, info — each with matching icon, color, and accessibility role.
Author: DevSnips Contributors
Usage Example: Call showToast('success'|'error'|'warning'|'info', title, message) after async results.
-->
<div
  id="status-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('success')" class="rounded-lg bg-green-600 px-4 py-2 text-sm font-medium text-white hover:bg-green-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-green-500 focus-visible:ring-offset-2">Success</button>
  <button onclick="showToast('error')" class="rounded-lg bg-red-600 px-4 py-2 text-sm font-medium text-white hover:bg-red-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-red-500 focus-visible:ring-offset-2">Error</button>
  <button onclick="showToast('warning')" class="rounded-lg bg-amber-500 px-4 py-2 text-sm font-medium text-white hover:bg-amber-600 focus:outline-none focus-visible:ring-2 focus-visible:ring-amber-500 focus-visible:ring-offset-2">Warning</button>
  <button onclick="showToast('info')" class="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-blue-500 focus-visible:ring-offset-2">Info</button>
</div>

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

    const variants = {
      success: {
        icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"/>',
        iconWrap: 'bg-green-100 text-green-600',
        ring: 'border-green-200',
      },
      error: {
        icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>',
        iconWrap: 'bg-red-100 text-red-600',
        ring: 'border-red-200',
      },
      warning: {
        icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/>',
        iconWrap: 'bg-amber-100 text-amber-600',
        ring: 'border-amber-200',
      },
      info: {
        icon: '<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"/>',
        iconWrap: 'bg-blue-100 text-blue-600',
        ring: 'border-blue-200',
      },
    };

    const copy = {
      success: { title: 'Saved successfully', body: 'Your changes are now live.' },
      error: { title: 'Something went wrong', body: 'Please try again in a moment.' },
      warning: { title: 'Almost there', body: 'Review the highlighted fields before saving.' },
      info: { title: 'Heads up', body: 'Scheduled maintenance starts in 1 hour.' },
    };

    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(type) {
      const v = variants[type] || variants.info;
      const c = copy[type] || copy.info;
      const toast = document.createElement('div');
      toast.className = `toast-item pointer-events-auto flex w-full items-start gap-3 rounded-xl border bg-white p-4 shadow-lg ring-1 ring-black/5 transition duration-300 ease-out ${v.ring}`;
      toast.setAttribute('role', type === 'error' || type === 'warning' ? 'alert' : 'status');
      toast.innerHTML = `
        <span class="flex h-8 w-8 shrink-0 items-center justify-center rounded-full ${v.iconWrap}">
          <svg class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">${v.icon}</svg>
        </span>
        <div class="min-w-0 flex-1">
          <p class="text-sm font-semibold text-gray-900">${c.title}</p>
          <p class="mt-0.5 text-sm text-gray-500">${c.body}</p>
        </div>
        <button type="button" class="toast-close shrink-0 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>`;
      root.appendChild(toast);

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

    window.showToast = showToast;
  })();
</script>
93 lines UTF-8 · LF · Spaces: 2

AI-ready

Available to your agent.

This component is reachable through the DevSnips CLI, MCP server and Skills integrations — one registry, one resource path.

Resource path

devsnips://components/toasts/status-toasts

Continue browsing

View all