Componentfeedback1.11 KB gzipZero dependencies
Callout
Tactile admission callout note with dashed borders, status tones and dismiss action.
Preview
Live Preview
INFOADMISSION NOTICE
Gate 4 opens at 19:30. Please present your digital stub at the turnstile.
Installation
Tokens guide →Add to your project via CLI (zero dependencies, code you own):
npx bigbullui add calloutOr install the full npm package:
npm install bigbulluiUsage
Open in StackBlitzimport { Callout } from "@/components/ui/callout";
<Callout title="ADMISSION NOTICE" variant="info">Gate 4 opens at 19:30.</Callout>Usage guidance
Use Callout when a ticket stub surface needs Tactile admission callout note with dashed borders, status tones and dismiss action. Keep props minimal and prefer composition with sibling stubs.
Avoid Callout for long form flows or dense data grids where a dedicated layout block fits better.
Source code
callout.tsxZero dependencies (only React + utils). Copy and paste directly into your project:
"use client";
import * as React from "react";
import { cn } from "./lib/utils";
export interface CalloutProps extends React.HTMLAttributes<HTMLDivElement> {
title?: string;
variant?: "info" | "success" | "warning" | "danger" | "neutral";
icon?: React.ReactNode;
dismissible?: boolean;
onDismiss?: () => void;
notched?: boolean;
className?: string;
children: React.ReactNode;
}
const VARIANT_STYLES = {
info: "border-foreground bg-card text-foreground",
success: "border-success bg-success/10 text-success",
warning: "border-warning bg-warning/10 text-warning",
danger: "border-destructive bg-destructive/10 text-destructive",
neutral: "border-border bg-secondary/50 text-foreground",
};
const VARIANT_BADGES = {
info: "bg-foreground text-background",
success: "bg-success text-white",
warning: "bg-warning text-black",
danger: "bg-destructive text-white",
neutral: "bg-secondary text-foreground",
};
export function Callout({
title,
variant = "info",
icon,
dismissible = false,
onDismiss,
notched = true,
className,
children,
...props
}: CalloutProps) {
const [dismissed, setDismissed] = React.useState(false);
if (dismissed) return null;
const handleDismiss = () => {
setDismissed(true);
onDismiss?.();
};
return (
<div
role="note"
className={cn(
"relative flex flex-col gap-2 rounded-lg border-2 border-dashed p-4 font-mono select-none shadow-xs",
VARIANT_STYLES[variant],
className
)}
{...props}
>
{notched && (
<>
<div
aria-hidden="true"
className="absolute -left-1.5 top-1/2 -translate-y-1/2 size-3 rounded-full border border-foreground bg-background"
/>
<div
aria-hidden="true"
className="absolute -right-1.5 top-1/2 -translate-y-1/2 size-3 rounded-full border border-foreground bg-background"
/>
</>
)}
{/* Header */}
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2">
<span
className={cn(
"rounded px-1.5 py-0.5 text-[9px] font-black uppercase tracking-wider",
VARIANT_BADGES[variant]
)}
>
{variant.toUpperCase()}
</span>
{title && (
<span className="text-xs font-bold uppercase tracking-wide text-foreground">
{title}
</span>
)}
</div>
{dismissible && (
<button
type="button"
onClick={handleDismiss}
aria-label="Dismiss callout"
className="cursor-pointer rounded border border-current px-1.5 py-0.2 text-[10px] font-bold opacity-70 hover:opacity-100 transition-opacity"
>
✕
</button>
)}
</div>
{/* Content */}
<div className="text-xs font-sans leading-relaxed text-muted-foreground">
{children}
</div>
</div>
);
}
Props
| Prop | Type | Description |
|---|---|---|
| title | string | Optional callout title |
| variant | "info" | "success" | "warning" | "danger" | "neutral" | Callout tone |
| dismissible | boolean | Whether user can close the callout |
| onDismiss | () => void | Callback on dismiss |