Callout

A component for displaying important information.

Default Callout
This is a default callout without any specific variant.
Information
This is an info callout used for general information.
Success
This is a success callout. The operation was completed successfully.
1import { Callout } from '@/components/ui/callout';
2
3export function Default() {
4 return (
5 <div className="flex w-full flex-col gap-4">
6 <Callout title="Default Callout">
7 This is a default callout without any specific variant.
8 </Callout>
9
10 <Callout variant="info" title="Information">
11 This is an info callout used for general information.
12 </Callout>
13
14 <Callout variant="warning" title="Warning">
15 This is a warning callout. Be careful interacting with this.
16 </Callout>
17
18 <Callout variant="danger" title="Error">
19 This is a danger callout. Something went wrong.
20 </Callout>
21
22 <Callout variant="success" title="Success">
23 This is a success callout. The operation was completed successfully.
24 </Callout>
25 </div>
26 );
27}

Installation

Copy and paste the following code into your project.
import {
Alert01Icon,
Alert02Icon,
CheckmarkCircle01Icon,
InformationCircleIcon,
} from '@hugeicons/core-free-icons';
import { HugeiconsIcon } from '@hugeicons/react';
import { cva, type VariantProps } from 'class-variance-authority';
import React from 'react';
import { cn } from '../lib/cn';
const calloutVariants = cva('flex w-full items-start gap-3 rounded-md border p-4 text-sm', {
variants: {
variant: {
default: 'bg-card/50 text-card-foreground border-border',
info: 'bg-info/10 text-info border-info/20',
warning: 'bg-warning/10 text-warning border-warning/20',
danger: 'bg-destructive/10 text-destructive border-destructive/20',
success: 'bg-success/10 text-success border-success/20',
},
},
defaultVariants: {
variant: 'default',
},
});
interface CalloutProps
extends React.HTMLAttributes<HTMLDivElement>, VariantProps<typeof calloutVariants> {
icon?: React.ReactNode;
title?: string;
}
const CalloutTitle = ({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) => (
<div
ref={ref}
className={cn('leading-none font-semibold tracking-tight', className)}
{...props}
/>
);
CalloutTitle.displayName = 'CalloutTitle';
const CalloutContent = ({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) => (
<div
ref={ref}
className={cn('text-muted-foreground/90 [&_p]:leading-relaxed', className)}
{...props}
/>
);
CalloutContent.displayName = 'CalloutContent';
const CalloutIcon = ({
className,
ref,
...props
}: React.HTMLAttributes<HTMLDivElement> & { ref?: React.Ref<HTMLDivElement> }) => (
<div
ref={ref}
aria-hidden="true"
className={cn('mt-0.5 shrink-0 text-base select-none', className)}
{...props}
/>
);
CalloutIcon.displayName = 'CalloutIcon';
const CalloutRoot = ({
className,
variant,
icon,
title,
children,
ref,
...props
}: CalloutProps & { ref?: React.Ref<HTMLDivElement> }) => {
const getIcon = () => {
if (icon) return icon;
switch (variant) {
case 'info':
return <HugeiconsIcon icon={InformationCircleIcon} size={18} />;
case 'warning':
return <HugeiconsIcon icon={Alert02Icon} size={18} />;
case 'danger':
return <HugeiconsIcon icon={Alert01Icon} size={18} />;
case 'success':
return <HugeiconsIcon icon={CheckmarkCircle01Icon} size={18} />;
default:
return null;
}
};
const calloutIcon = getIcon();
const role = variant === 'danger' || variant === 'warning' ? 'alert' : 'region';
return (
<div ref={ref} role={role} className={cn(calloutVariants({ variant }), className)} {...props}>
{calloutIcon ? <CalloutIcon>{calloutIcon}</CalloutIcon> : null}
<div className="flex-1 space-y-1">
{title ? <CalloutTitle>{title}</CalloutTitle> : null}
<CalloutContent>{children}</CalloutContent>
</div>
</div>
);
};
CalloutRoot.displayName = 'Callout';
const Callout = Object.assign(CalloutRoot, {
Title: CalloutTitle,
Content: CalloutContent,
Icon: CalloutIcon,
});
export { Callout, calloutVariants };
export type { CalloutProps };
Make sure to update the import paths according to your project structure.

Anatomy

import { Callout } from '@/components/ui/callout';
<Callout variant="info" title="Note">
This is a callout with information.
</Callout>

Examples

Variants

The Callout component comes with different variants to indicate the type of message.
<Callout>Default callout</Callout>
<Callout variant="info">Info callout</Callout>
<Callout variant="warning">Warning callout</Callout>
<Callout variant="danger">Danger callout</Callout>
<Callout variant="success">Success callout</Callout>

Custom Icon

You can override the default icon by passing the icon prop.
<Callout icon={<MyCustomIcon />}>Callout with custom icon</Callout>

API Reference

Callout

PropTypeDefaultDescription
variant"default" | "info" | "warning" | "danger" | "success""default"The callout style.
iconReact.ReactNodeCustom icon to display. If not provided, a default icon is used based on the variant.
titlestringThe title of the callout.
classNamestringAdditional CSS class names.
childrenReact.ReactNodeThe callout content.