Components
Alert
Displays a callout for user attention with support for different variants and dismissible actions.
import { Alert, AlertAction, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import { Info } from 'lucide-react';
export function AlertDemo() {
return (
<div className='flex flex-col gap-6'>
<div className='flex flex-col gap-2'>
<Alert
dismissible
onDismiss={() => {
console.log('Alert dismissed');
}}
icon={<Info />}
>
<AlertTitle>Information</AlertTitle>
<AlertDescription>
This is a default alert. You can add any content here.
</AlertDescription>
<AlertAction>
<Button size='sm'>Learn more</Button>
</AlertAction>
</Alert>
</div>
</div>
);
}Installation
CLI
npx shadcn@latest add "https://maksud.dev/r/alert"Manual
Install the following dependencies:
npm install class-variance-authority lucide-reactCopy and paste the following code into your project.
import { cva, type VariantProps } from 'class-variance-authority';
import { X } from 'lucide-react';
import type * as React from 'react';
import { cn } from '@/lib/utils';
const alertDissmissButtonVariants = cva(
'absolute top-2 right-2 rounded-md p-1 text-muted-foreground/80 hover:text-foreground',
{
variants: {
variant: {
default: 'hover:bg-accent',
destructive: 'hover:bg-destructive/10',
success: 'hover:bg-success/10',
warning: 'hover:bg-attention/10',
},
},
defaultVariants: {
variant: 'default',
},
}
);
const alertVariants = cva(
'relative grid w-full grid-cols-[0_1fr] items-start gap-y-0.5 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5 [&>svg]:text-current',
{
variants: {
variant: {
default: 'bg-surface/5 text-card-foreground',
success:
'border-success/30 bg-success/5 text-success *:data-[slot=alert-description]:text-success/90 [&>svg]:text-success',
warning:
'border-attention/30 bg-attention/5 text-attention *:data-[slot=alert-description]:text-attention/90 [&>svg]:text-attention',
destructive:
'border-destructive/30 bg-destructive/5 text-destructive *:data-[slot=alert-description]:text-destructive/90 [&>svg]:text-destructive',
},
},
defaultVariants: {
variant: 'default',
},
}
);
interface AlertProps extends React.ComponentProps<'div'>, VariantProps<typeof alertVariants> {
icon?: React.ReactNode;
dismissible?: boolean;
onDismiss?: () => void;
}
function Alert({
className,
variant,
icon,
dismissible,
onDismiss,
children,
...props
}: AlertProps) {
return (
<div
data-slot='alert'
role='alert'
className={cn(alertVariants({ variant }), className, 'shadow')}
{...props}
>
{icon}
<div className='col-start-2'>{children}</div>
{dismissible ? (
<button
type='button'
aria-label='Dismiss'
onClick={onDismiss}
className={cn(alertDissmissButtonVariants({ variant }))}
>
<X className='size-4' />
</button>
) : null}
</div>
);
}
function AlertTitle({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot='alert-title'
className={cn(
'col-start-2 line-clamp-1 min-h-4 font-semibold text-base tracking-tight',
className
)}
{...props}
/>
);
}
function AlertDescription({ className, ...props }: React.ComponentProps<'div'>) {
return (
<div
data-slot='alert-description'
className={cn(
'col-start-2 grid justify-items-start gap-2 text-foreground text-sm [&_p]:leading-relaxed',
className
)}
{...props}
/>
);
}
function AlertAction({ className, ...props }: React.ComponentProps<'div'>) {
return <div data-slot='alert-action' className={cn('col-start-2 mt-2', className)} {...props} />;
}
export { Alert, AlertAction, AlertDescription, AlertTitle };Layout
Import the parts and compose them together.
import { Alert, AlertAction, AlertDescription, AlertTitle } from "@/components/ui/alert";
export default function Example() {
return (
<Alert>
<AlertTitle>Alert Title</AlertTitle>
<AlertDescription>
Alert description or content goes here.
</AlertDescription>
</Alert>
);
}Examples
Variants
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { AlertTriangle, CheckCircle, Info, TriangleAlert } from 'lucide-react';
export function AlertVariantsDemo() {
return (
<div className='grid gap-4'>
<Alert>
<Info className='size-4' />
<AlertTitle>Default Alert</AlertTitle>
<AlertDescription>
This is the default alert variant. It's perfect for general information and neutral
messages.
</AlertDescription>
</Alert>
<Alert variant='success'>
<CheckCircle className='size-4' />
<AlertTitle>Success Alert</AlertTitle>
<AlertDescription>
Use this variant to indicate successful operations, confirmations, or positive outcomes.
</AlertDescription>
</Alert>
<Alert variant='warning'>
<TriangleAlert className='size-4' />
<AlertTitle>Warning Alert</AlertTitle>
<AlertDescription>
This variant draws attention to potential issues or important information that requires
user attention.
</AlertDescription>
</Alert>
<Alert variant='destructive'>
<AlertTriangle className='size-4' />
<AlertTitle>Destructive Alert</AlertTitle>
<AlertDescription>
Use this for errors, failures, or critical issues that need immediate attention from the
user.
</AlertDescription>
</Alert>
</div>
);
}The Alert component supports four variants: default, success, warning, and destructive.
Dismissible
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { CheckCircle, Info, TriangleAlert } from 'lucide-react';
import { useState } from 'react';
export function AlertDismissibleDemo() {
const [alerts, setAlerts] = useState({
info: true,
success: true,
warning: true,
error: true,
});
const dismissAlert = (type: keyof typeof alerts) => {
setAlerts((prev) => ({ ...prev, [type]: false }));
};
return (
<div className='flex flex-col gap-4'>
{alerts.info && (
<Alert dismissible onDismiss={() => dismissAlert('info')}>
<Info className='size-4' />
<AlertTitle>Information</AlertTitle>
<AlertDescription>
This alert can be dismissed. Click the × button to remove it.
</AlertDescription>
</Alert>
)}
{alerts.success && (
<Alert variant='success' dismissible onDismiss={() => dismissAlert('success')}>
<CheckCircle className='size-4' />
<AlertTitle>Success</AlertTitle>
<AlertDescription>
Operation completed successfully! This alert can be dismissed.
</AlertDescription>
</Alert>
)}
{alerts.warning && (
<Alert variant='warning' dismissible onDismiss={() => dismissAlert('warning')}>
<TriangleAlert className='size-4' />
<AlertTitle>Warning</AlertTitle>
<AlertDescription>
Please review your settings. This warning can be dismissed.
</AlertDescription>
</Alert>
)}
{alerts.error && (
<Alert variant='destructive' dismissible onDismiss={() => dismissAlert('error')}>
<TriangleAlert className='size-4' />
<AlertTitle>Error</AlertTitle>
<AlertDescription>
Something went wrong. This error alert can be dismissed.
</AlertDescription>
</Alert>
)}
</div>
);
}Add the dismissible prop to make alerts dismissible with a close button.
With Actions
import { Alert, AlertAction, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { Button } from '@/components/ui/button';
import { TriangleAlert } from 'lucide-react';
export function AlertWithActionsDemo() {
return (
<div className='flex flex-col gap-6'>
<div className='flex flex-col gap-2'>
<span className='text-muted-foreground text-sm'>Warning with Multiple Actions</span>
<Alert variant='warning'>
<TriangleAlert className='size-4' />
<AlertTitle>Storage Almost Full</AlertTitle>
<AlertDescription>
Your storage is 90% full. Consider upgrading your plan or cleaning up files.
</AlertDescription>
<AlertAction>
<div className='flex gap-2'>
<Button size='sm' variant='warning'>
Upgrade Plan
</Button>
<Button size='sm' variant='outline'>
Clean Up
</Button>
</div>
</AlertAction>
</Alert>
</div>
<div className='flex flex-col gap-2'>
<span className='text-muted-foreground text-sm'>Error with Dismissible Action</span>
<Alert variant='destructive' dismissible>
<TriangleAlert className='size-4' />
<AlertTitle>Connection Failed</AlertTitle>
<AlertDescription>
Unable to connect to the server. Please check your internet connection.
</AlertDescription>
<AlertAction>
<Button size='sm' variant='destructive'>
Retry Connection
</Button>
</AlertAction>
</Alert>
</div>
</div>
);
}Use AlertAction to add interactive elements like buttons to your alerts.
API Reference
| Prop | Description |
|---|---|
variant | The visual style variant of the alert. |
icon | The icon to display in the alert. Not using an icon is perfectly fine - alerts work great with or without icons. |
dismissible | Whether the alert can be dismissed with a close button. |
onDismiss | Callback function called when the alert is dismissed. Required when dismissible is true. |