Core Component
Banner
Full-width alert banner for system-level messages with four semantic variants and optional dismiss.
Preview
New model available: Claude 3.5 Sonnet.
Context window is 90% full.
API key is invalid. Check your settings.
Workspace settings saved.
Source
Full component implementation using the design system tokens.
tsx
"use client";
import { useState } from "react";
import { X, CheckCircle2, AlertTriangle, AlertCircle, Info } from "lucide-react";
const variantStyles = {
info: { bg: "bg-blue-500/10 border-blue-500/20", icon: Info, iconColor: "text-blue-500" },
warning: { bg: "bg-amber-500/10 border-amber-500/20", icon: AlertTriangle, iconColor: "text-amber-500" },
error: { bg: "bg-red-500/10 border-red-500/20", icon: AlertCircle, iconColor: "text-red-500" },
success: { bg: "bg-green-500/10 border-green-500/20", icon: CheckCircle2, iconColor: "text-green-500" },
};
export function DSBanner({
variant = "info", children, dismissable = false, onDismiss,
}: {
variant?: "info" | "warning" | "error" | "success";
children: React.ReactNode;
dismissable?: boolean;
onDismiss?: () => void;
}) {
const [dismissed, setDismissed] = useState(false);
const style = variantStyles[variant];
const Icon = style.icon;
const handleDismiss = () => { setDismissed(true); onDismiss?.(); };
return (
<div
className={`flex items-start gap-3 px-4 py-3 rounded-xl border w-full ${style.bg}`}
style={{
opacity: dismissed ? 0 : 1,
maxHeight: dismissed ? 0 : 200,
overflow: "hidden",
padding: dismissed ? "0 16px" : undefined,
transition: "opacity 200ms var(--ease-out), max-height 200ms var(--ease-out), padding 200ms var(--ease-out)",
}}
role={variant === "error" || variant === "warning" ? "alert" : "status"}
>
<Icon className={`w-5 h-5 shrink-0 mt-0.5 ${style.iconColor}`} />
<div className="flex-1 min-w-0 text-sm text-foreground">{children}</div>
{dismissable && (
<button onClick={handleDismiss} className="shrink-0 p-0.5 text-tertiary hover:text-foreground transition-colors active:scale-[0.95]"
style={{ transitionTimingFunction: "var(--ease-out)" }} aria-label="Dismiss">
<X className="w-4 h-4" />
</button>
)}
</div>
);
}Props
All available props with types and defaults.
| Prop | Type | Default | Description |
|---|---|---|---|
children* | ReactNode | — | Banner content |
variant | 'info' | 'warning' | 'error' | 'success' | 'info' | Semantic variant |
dismissable | boolean | false | Shows a dismiss button |
onDismiss | () => void | — | Called when dismiss button is clicked |
Variants
Info
General information or tips.
New model available: Claude 3.5 Sonnet.
tsx
<DSBanner variant="info">New model available: Claude 3.5 Sonnet.</DSBanner>Warning
Caution or degraded state.
Context window is 90% full.
tsx
<DSBanner variant="warning">Context window is 90% full.</DSBanner>Error
Errors that need attention.
API key is invalid. Check your settings.
tsx
<DSBanner variant="error">API key is invalid. Check your settings.</DSBanner>Success
Confirmation of successful operation.
Workspace settings saved.
tsx
<DSBanner variant="success">Workspace settings saved.</DSBanner>Dismissable
Banner with a close button.
New model available: Claude 3.5 Sonnet.
tsx
<DSBanner variant="info" dismissable>You can dismiss this message.</DSBanner>Prompt Guide
Prompt Guide — Banner
Use for
- System-wide announcements (new model, maintenance)
- Rate limit or quota warnings
- API key or configuration errors
- Successful deployment or save confirmations
Don't use for
- Inline field validation — use Input error prop
- Transient feedback — use Toast instead
- Long content — keep to 1-2 sentences
AI Context
Banner is page-level, Toast is transient. Use Banner for persistent system messages that the user should act on. Dismiss animation collapses height and fades out simultaneously. role='alert' for error/warning ensures screen reader announcement.