|Design System

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.
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.

PropTypeDescription
children*ReactNodeBanner content
variant'info' | 'warning' | 'error' | 'success'Semantic variant
dismissablebooleanShows a dismiss button
onDismiss() => voidCalled 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.

tsx
<DSBanner variant="warning">Context window is 90% full.</DSBanner>

Error

Errors that need attention.

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.