Components · Feedback
Alert
A message on the page, neutral or destructive.
3.8% of the 2,062 sites in The UI Index have a alert (78 sites).
Your changes are saved
The preview updates within a minute.
Payment failed
Your card was declined. Update it to keep your plan.
Your changes are saved
The preview updates within a minute.
Payment failed
Your card was declined. Update it to keep your plan.
Both previews render the same markup; the HTML tab below is that markup without a framework.
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
Or copy the files below into your project. They need clsx, tailwind-merge, and the Caseroom theme. The HTML needs only the compiled CSS.
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>
);
}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>;---
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>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>;<div class="grid w-full max-w-lg gap-4">
<div role="status" class="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 bg-card text-card-foreground">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="8" cy="8" r="6.5"></circle><path d="M5.5 8.2l1.8 1.8 3.2-3.8"></path></svg>
<div class="col-start-2 font-medium tracking-[-0.005em]">Your changes are saved</div>
<div data-alert-body class="col-start-2 text-muted-foreground"> The preview updates within a minute. </div>
</div>
<div role="alert" class="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 border-destructive/50 bg-card text-destructive [&_[data-alert-body]]:text-destructive/90">
<svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" aria-hidden="true"><circle cx="8" cy="8" r="6.5"></circle><path d="M8 4.5v4M8 11h.01"></path></svg>
<div class="col-start-2 font-medium tracking-[-0.005em]">Payment failed</div>
<div data-alert-body class="col-start-2 text-muted-foreground"> Your card was declined. Update it to keep your plan. </div>
</div>
</div>