Maksud UI
Components

Alert

Displays a callout for user attention with support for different variants and dismissible actions.

API
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-react

Copy 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

PropDescription
variantThe visual style variant of the alert.
iconThe icon to display in the alert. Not using an icon is perfectly fine - alerts work great with or without icons.
dismissibleWhether the alert can be dismissed with a close button.
onDismissCallback function called when the alert is dismissed. Required when dismissible is true.