# Alert (Caseroom component)

A message on the page, neutral or destructive. Black and white, dark mode, shadcn-compatible; React, Astro and plain HTML.

3.8% of the 2,062 sites in The UI Index have a alert (78 sites).

## Install

- React: `npx shadcn@latest add https://www.themes.dev/caseroom/r/alert.json`
- Astro: `npx shadcn@latest add https://www.themes.dev/caseroom/r/astro/alert.json`
- HTML: https://www.themes.dev/caseroom/r/html/alert.html (with https://www.themes.dev/caseroom/r/html/caseroom.css)

Page: https://www.themes.dev/caseroom/components/alert/ · Rules for agents: https://www.themes.dev/caseroom/AGENT.md

## Code

### alert.astro

```astro
---
import type { HTMLAttributes } from 'astro/types';
import { cn } from '@/lib/utils';
import { alertBody, alertTitle, alertVariants, type AlertVariants } from './alert.variants';

type Props = Omit<HTMLAttributes<'div'>, 'title'> & AlertVariants & { title?: string };
const { variant, title, class: className, ...rest } = Astro.props;
---

<div role={variant === 'destructive' ? 'alert' : 'status'} class={cn(alertVariants({ variant }), className)} {...rest}>
  <slot name="icon" />
  {title && <div class={alertTitle}>{title}</div>}
  {Astro.slots.has('default') && <div data-alert-body class={alertBody}><slot /></div>}
</div>
```

### alert.tsx

```tsx
import type { HTMLAttributes, ReactNode } from 'react';
import { cn } from '@/lib/utils';
import { alertBody, alertTitle, alertVariants, type AlertVariants } from './alert.variants';

export type AlertProps = Omit<HTMLAttributes<HTMLDivElement>, 'title'> &
  AlertVariants & { title?: ReactNode; icon?: ReactNode };

/** A message on the page. role="alert" only for the destructive variant, so screen readers announce errors. */
export function Alert({ variant, title, icon, className, children, ...props }: AlertProps) {
  return (
    <div role={variant === 'destructive' ? 'alert' : 'status'} className={cn(alertVariants({ variant }), className)} {...props}>
      {icon}
      {title && <div className={alertTitle}>{title}</div>}
      {children && <div data-alert-body="" className={alertBody}>{children}</div>}
    </div>
  );
}
```

### alert.variants.ts

```tsx
import { cva, type VariantProps } from 'class-variance-authority';

export const alertVariants = cva(
  'relative grid w-full grid-cols-[0_1fr] items-start gap-y-1 rounded-lg border px-4 py-3 text-sm has-[>svg]:grid-cols-[1rem_1fr] has-[>svg]:gap-x-3 [&>svg]:size-4 [&>svg]:translate-y-0.5',
  {
    variants: {
      variant: {
        default: 'bg-card text-card-foreground',
        destructive: 'border-destructive/50 bg-card text-destructive [&_[data-alert-body]]:text-destructive/90',
      },
    },
    defaultVariants: { variant: 'default' },
  },
);
export const alertTitle = 'col-start-2 font-medium tracking-[-0.005em]';
export const alertBody = 'col-start-2 text-muted-foreground';
export type AlertVariants = VariantProps<typeof alertVariants>;
```
