Feedback
Callout
An inline highlight box for docs, forms and explanatory copy — info, success, warning and danger variants with a tinted accent bar and default icon per variant.
Preview in your theme
Loading preview…
Installation
npx shadcn@latest add https://ui.zyeon.ai/r/callout.jsonPrompt
The prompt behind this component — paste it into your AI assistant to recreate or adapt it.
Build a React + TypeScript + Tailwind "Callout" component using lucide-react
icons (no other runtime dependencies).
Contract
- Export a forwardRef div extending React.HTMLAttributes<HTMLDivElement>;
spread remaining props on the root and merge className via cn().
- Props: variant = "info" | "success" | "warning" | "danger" (default "info");
title?: string; icon?: ReactNode (per-variant defaults: Info / CircleCheck /
TriangleAlert / OctagonAlert; pass null to render no icon); children is the
body copy.
Behavior
- Purely presentational — no state, no effects, no "use client" directive.
- role follows the variant: "danger" gets role="alert" (assertive, announced
immediately); every other variant gets role="note" (ancillary content, no
live-region behavior) since a callout is read in place, not announced as an
interruption.
- The icon renders only when icon !== null: icon === undefined falls back to
the variant's default glyph, any other value overrides it.
Rendering & styling
- Semantic tokens only, no hardcoded colors. A variant → color lookup maps to
CSS variables: info = var(--primary), success = var(--chart-2),
warning = var(--chart-4), danger = var(--destructive).
- The color is applied via inline style + color-mix (not a fixed Tailwind
palette class) so the accent stays correct if a project remaps its tokens:
a 3px border-inline-start in the variant color, a background of
color-mix(in oklab, <color> 8%, transparent), and the icon/title tinted
with the same color. Body copy stays text-foreground/90 for readable
contrast against the tinted background in both themes.
- cn() merges the consumer className; no animation, so no reduced-motion
branch is needed.
Customization levers
- Add a variant: one VARIANT_COLORS entry (any CSS color token) plus one
DEFAULT_ICONS entry — layout and roles are untouched.
- Border style: swap the inline border-inline-start for a full border
(border + border-color via the same color-mix value) for a boxed-admonition
look instead of the accent-bar look.
- Density: px-4 py-3 text-sm is the only sizing; pass py-2 text-xs via
className for a compact strip inside tight forms, or px-5 py-4 for a
docs-page callout with more breathing room.
- Drop the icon with icon={null}, or pass any lucide-react (or custom) node
to brand the callout.
- Omit title for a plain single-paragraph note; pass title for a labeled
admonition (Note/Tip/Warning/Danger-style headings).Concepts
- Variant-driven accent color — a single CSS variable per variant feeds the border, background tint and icon/title color together, so remapping a project's theme tokens re-colors every callout for free.
- Inline notice, not a page-level one — a callout lives inside the reading flow (a docs paragraph, a form's helper text) instead of pinning to the top of the page like a Banner.
- Semantic live-region role —
dangerisrole="alert"(interrupts screen readers immediately); the rest arerole="note"(ancillary, read in place, not urgent) — urgency is an accessibility semantic, not just a color. - Default icon per variant — Info / CircleCheck / TriangleAlert / OctagonAlert ship out of the box; the
iconprop overrides it andicon={null}removes it, keeping the common case zero-config. - Tinted background via color-mix — an 8% mix keeps the panel legible on both light and dark backgrounds without maintaining a second dark-mode color table.