Left Accent Alert
Original · freeAlerts with a coloured left accent bar and icon.
Copy prompt gives Claude Code, Cursor or v0 a ready-to-paste prompt that recreates this exact component.
npx shadcn@latest add https://webinnoventix.com/r/alert-left-accent.json"use client";
import { useState, type ReactElement } from "react";
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
type Tone = "info" | "success" | "warning" | "error";
type AlertItem = {
id: string;
tone: Tone;
title: string;
message: string;
action?: { label: string; href: string };
};
type ToneStyle = {
accent: string;
panel: string;
iconWrap: string;
title: string;
body: string;
action: string;
focusRing: string;
Icon: () => ReactElement;
};
const InfoIcon = () => (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-5 w-5">
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.75" />
<path d="M12 11v5" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" />
<circle cx="12" cy="7.75" r="1.15" fill="currentColor" />
</svg>
);
const SuccessIcon = () => (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-5 w-5">
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.75" />
<path d="m8.25 12.4 2.4 2.4 4.85-5.1" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
</svg>
);
const WarningIcon = () => (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-5 w-5">
<path d="M12 3.4 21 19H3l9-15.6Z" stroke="currentColor" strokeWidth="1.75" strokeLinejoin="round" />
<path d="M12 9.5v4" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" />
<circle cx="12" cy="16.4" r="1.1" fill="currentColor" />
</svg>
);
const ErrorIcon = () => (
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-5 w-5">
<circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.75" />
<path d="m9.25 9.25 5.5 5.5M14.75 9.25l-5.5 5.5" stroke="currentColor" strokeWidth="1.75" strokeLinecap="round" />
</svg>
);
const TONES: Record<Tone, ToneStyle> = {
info: {
accent: "bg-sky-500 dark:bg-sky-400",
panel: "bg-sky-50 dark:bg-sky-950/40",
iconWrap: "text-sky-600 dark:text-sky-300",
title: "text-sky-900 dark:text-sky-100",
body: "text-sky-700/90 dark:text-sky-200/80",
action: "text-sky-700 hover:text-sky-900 dark:text-sky-300 dark:hover:text-sky-100 decoration-sky-400/50",
focusRing: "focus-visible:ring-sky-500 dark:focus-visible:ring-sky-400",
Icon: InfoIcon,
},
success: {
accent: "bg-emerald-500 dark:bg-emerald-400",
panel: "bg-emerald-50 dark:bg-emerald-950/40",
iconWrap: "text-emerald-600 dark:text-emerald-300",
title: "text-emerald-900 dark:text-emerald-100",
body: "text-emerald-700/90 dark:text-emerald-200/80",
action: "text-emerald-700 hover:text-emerald-900 dark:text-emerald-300 dark:hover:text-emerald-100 decoration-emerald-400/50",
focusRing: "focus-visible:ring-emerald-500 dark:focus-visible:ring-emerald-400",
Icon: SuccessIcon,
},
warning: {
accent: "bg-amber-500 dark:bg-amber-400",
panel: "bg-amber-50 dark:bg-amber-950/40",
iconWrap: "text-amber-600 dark:text-amber-300",
title: "text-amber-900 dark:text-amber-100",
body: "text-amber-800/90 dark:text-amber-200/80",
action: "text-amber-800 hover:text-amber-950 dark:text-amber-300 dark:hover:text-amber-100 decoration-amber-400/50",
focusRing: "focus-visible:ring-amber-500 dark:focus-visible:ring-amber-400",
Icon: WarningIcon,
},
error: {
accent: "bg-rose-500 dark:bg-rose-400",
panel: "bg-rose-50 dark:bg-rose-950/40",
iconWrap: "text-rose-600 dark:text-rose-300",
title: "text-rose-900 dark:text-rose-100",
body: "text-rose-700/90 dark:text-rose-200/80",
action: "text-rose-700 hover:text-rose-900 dark:text-rose-300 dark:hover:text-rose-100 decoration-rose-400/50",
focusRing: "focus-visible:ring-rose-500 dark:focus-visible:ring-rose-400",
Icon: ErrorIcon,
},
};
const INITIAL_ALERTS: AlertItem[] = [
{
id: "deploy",
tone: "success",
title: "Deployment finished",
message: "webinnoventix.com is live on the edge network. All 214 pages passed the post-build health check.",
action: { label: "View build log", href: "#build-log" },
},
{
id: "ssl",
tone: "info",
title: "Certificate renews automatically",
message: "Your SSL certificate renews on 2 Aug 2026. No action is needed — we handle the renewal 30 days early.",
},
{
id: "quota",
tone: "warning",
title: "Image CDN nearing its limit",
message: "You have used 88% of this month's 100 GB transfer allowance. Traffic beyond the cap is billed at $0.04/GB.",
action: { label: "Upgrade plan", href: "#billing" },
},
{
id: "form",
tone: "error",
title: "Contact form is not sending",
message: "The RESEND_API_KEY environment variable is missing, so 6 lead submissions are queued and undelivered.",
action: { label: "Add API key", href: "#env" },
},
];
export default function AlertLeftAccent() {
const reduceMotion = useReducedMotion();
const [alerts, setAlerts] = useState<AlertItem[]>(INITIAL_ALERTS);
const dismiss = (id: string) => {
setAlerts((prev) => prev.filter((a) => a.id !== id));
};
const reset = () => setAlerts(INITIAL_ALERTS);
return (
<section className="relative w-full bg-white px-4 py-20 sm:px-6 dark:bg-neutral-950">
<style>{`
@keyframes wialaAccentPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.55; }
}
.wiala-live-accent { animation: wialaAccentPulse 2.6s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
.wiala-live-accent { animation: none; }
}
`}</style>
<div className="mx-auto max-w-2xl">
<header className="mb-8">
<span className="inline-block text-xs font-semibold uppercase tracking-[0.18em] text-indigo-600 dark:text-indigo-400">
System status
</span>
<h2 className="mt-2 text-2xl font-bold tracking-tight text-neutral-900 sm:text-3xl dark:text-neutral-50">
Left-accent alerts
</h2>
<p className="mt-2 text-sm text-neutral-600 dark:text-neutral-400">
Four tones, each with a coloured accent bar and icon. Every alert can be dismissed or acted on.
</p>
</header>
<div className="space-y-3.5">
<AnimatePresence initial={false} mode="popLayout">
{alerts.map((alert) => {
const t = TONES[alert.tone];
const Icon = t.Icon;
const isError = alert.tone === "error";
return (
<motion.div
key={alert.id}
layout={reduceMotion ? false : true}
initial={reduceMotion ? false : { opacity: 0, x: -16, height: 0 }}
animate={reduceMotion ? { opacity: 1 } : { opacity: 1, x: 0, height: "auto" }}
exit={reduceMotion ? { opacity: 0 } : { opacity: 0, x: 24, height: 0, marginBottom: 0 }}
transition={reduceMotion ? { duration: 0 } : { type: "spring", stiffness: 380, damping: 34 }}
role={isError ? "alert" : "status"}
aria-live={isError ? "assertive" : "polite"}
className={`relative flex gap-3 overflow-hidden rounded-lg border border-black/5 pl-4 pr-3 py-3.5 shadow-sm ring-1 ring-black/[0.02] dark:border-white/10 dark:ring-white/[0.02] ${t.panel}`}
>
<span
aria-hidden="true"
className={`absolute inset-y-0 left-0 w-1.5 ${t.accent} ${isError ? "wiala-live-accent" : ""}`}
/>
<span className={`mt-0.5 shrink-0 ${t.iconWrap}`}>
<Icon />
</span>
<div className="min-w-0 flex-1">
<p className={`text-sm font-semibold ${t.title}`}>{alert.title}</p>
<p className={`mt-1 text-sm leading-relaxed ${t.body}`}>{alert.message}</p>
{alert.action && (
<a
href={alert.action.href}
className={`mt-2.5 inline-flex items-center gap-1 rounded text-sm font-semibold underline underline-offset-4 outline-none transition-colors focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:ring-offset-transparent ${t.action} ${t.focusRing}`}
>
{alert.action.label}
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-3.5 w-3.5">
<path d="M5 12h14M13 6l6 6-6 6" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" />
</svg>
</a>
)}
</div>
<button
type="button"
onClick={() => dismiss(alert.id)}
aria-label={`Dismiss ${alert.title}`}
className={`-mr-1 mt-0.5 grid h-7 w-7 shrink-0 place-items-center rounded-md text-neutral-500 outline-none transition-colors hover:bg-black/5 hover:text-neutral-800 focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-offset-transparent dark:text-neutral-400 dark:hover:bg-white/10 dark:hover:text-neutral-100 ${t.focusRing}`}
>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-4 w-4">
<path d="M6 6l12 12M18 6 6 18" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" />
</svg>
</button>
</motion.div>
);
})}
</AnimatePresence>
</div>
<AnimatePresence>
{alerts.length === 0 && (
<motion.div
initial={reduceMotion ? false : { opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0 }}
className="rounded-lg border border-dashed border-neutral-300 bg-neutral-50 px-4 py-10 text-center dark:border-neutral-700 dark:bg-neutral-900"
>
<p className="text-sm font-medium text-neutral-700 dark:text-neutral-300">
You are all caught up — no active alerts.
</p>
<button
type="button"
onClick={reset}
className="mt-4 inline-flex items-center gap-1.5 rounded-md bg-indigo-600 px-3.5 py-2 text-sm font-semibold text-white outline-none transition-colors hover:bg-indigo-500 focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 focus-visible:ring-offset-white dark:focus-visible:ring-offset-neutral-950"
>
<svg viewBox="0 0 24 24" fill="none" aria-hidden="true" className="h-4 w-4">
<path d="M4 12a8 8 0 1 1 2.3 5.6M4 12V7m0 5h5" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" />
</svg>
Restore alerts
</button>
</motion.div>
)}
</AnimatePresence>
</div>
</section>
);
}Dependencies
Licence
Built by Web Innoventix. Free for personal and commercial use, no attribution required.
Built by Web Innoventix
Need a custom interface, a full website, or SEO that gets you cited by AI? We design, build and rank it end to end.
Get a free quoteSimilar components
Browse all →
Soft Variants Alert
OriginalSoft-tinted alerts: success, info, warning and error, each with an icon.

Solid Variants Alert
OriginalSolid-colour alerts across the four states.

Outline Variants Alert
OriginalOutlined alerts across the four states.

Dismissible Alert
OriginalDismissible alerts with a working close button.

With Action Alert
OriginalAn alert with title, body and action buttons.
Icon Large Alert
OriginalAn alert led by a large circular icon.

Banner Top Alert
OriginalA full-width top announcement banner, dismissible.

Toast Stack Alert
OriginalA stack of dismissible toasts in a corner.

Toast Slide Alert
OriginalA toast that slides in with an icon and auto-dismiss progress.

Progress Alert
OriginalAn alert with a countdown progress bar.

Gradient Alert
OriginalA gradient promo banner alert with a call to action.

Inline Form Alert
OriginalAn alert containing an inline email input and button.

