Alert
Displays a callout for user attention.
Success! Your changes have been saved
This is an alert with icon, title and description.
This Alert has a title and an icon. No description.
Unable to process your payment.
Please verify your billing information and try again.
- Check your card details
- Ensure sufficient funds
- Verify billing address
import { css } from 'remix/component'
import { Alert, AlertDescription, AlertTitle } from '#app/ui/alert.tsx'
import { AlertCircleIcon, CheckCircle2Icon, PopcornIcon } from '#app/ui/icons.tsx'
export function AlertDemo() {import { css } from 'remix/component'
import { Alert, AlertDescription, AlertTitle } from '#app/ui/alert.tsx'
import { AlertCircleIcon, CheckCircle2Icon, PopcornIcon } from '#app/ui/icons.tsx'
export function AlertDemo() {
return () => (
<div
mix={css({
display: 'grid',
width: '100%',
maxWidth: '36rem',
alignItems: 'start',
gap: '1rem',
})}
>
<Alert>
<CheckCircle2Icon />
<AlertTitle>Success! Your changes have been saved</AlertTitle>
<AlertDescription>This is an alert with icon, title and description.</AlertDescription>
</Alert>
<Alert>
<PopcornIcon />
<AlertTitle>This Alert has a title and an icon. No description.</AlertTitle>
</Alert>
<Alert variant="destructive">
<AlertCircleIcon />
<AlertTitle>Unable to process your payment.</AlertTitle>
<AlertDescription>
<p>Please verify your billing information and try again.</p>
<ul
mix={css({
listStylePosition: 'inside',
listStyleType: 'disc',
fontSize: '0.875rem',
lineHeight: 'calc(1.25 / 0.875)',
})}
>
<li>Check your card details</li>
<li>Ensure sufficient funds</li>
<li>Verify billing address</li>
</ul>
</AlertDescription>
</Alert>
</div>
)
}Installation
$ bunx --bun shadcn@latest add https://www.shadcn-remix.com/r/alert.json$ npx shadcn@latest add https://www.shadcn-remix.com/r/alert.json$ pnpm dlx shadcn@latest add https://www.shadcn-remix.com/r/alert.json$ yarn dlx shadcn@latest add https://www.shadcn-remix.com/r/alert.jsonInstall the following dependencies:
$ bun add remix$ npm install remix$ pnpm add remix$ yarn add remixCopy and paste the following code into your project.
import { css, type CSSMixinDescriptor, type Handle, type Props } from 'remix/component'
export type AlertVariant = 'default' | 'destructive'
export interface AlertVariantOptions {
variant?: AlertVariant
}
export interface AlertProps extends Props<'div'>, AlertVariantOptions {}
const base = css({
position: 'relative',
display: 'grid',
width: '100%',
gridTemplateColumns: '0 1fr',
alignItems: 'start',
rowGap: '0.125rem',
borderRadius: 'var(--radius)',
borderWidth: '1px',
paddingInline: '1rem',
paddingBlock: '0.75rem',
fontSize: '0.875rem',
lineHeight: 'calc(1.25 / 0.875)',
'&:has(>svg)': { gridTemplateColumns: '1rem 1fr', columnGap: '0.75rem' },
'& > svg': { width: '1rem', height: '1rem', translate: '0 0.125rem', color: 'currentColor' },
})
const variants: Record<AlertVariant, CSSMixinDescriptor> = {
default: css({ backgroundColor: 'var(--card)', color: 'var(--card-foreground)' }),
destructive: css({
backgroundColor: 'var(--card)',
color: 'var(--destructive)',
'& > svg': { color: 'currentColor' },
}),
}
const alertTitleStyles = css({
gridColumnStart: '2',
overflow: 'hidden',
display: '-webkit-box',
WebkitBoxOrient: 'vertical',
WebkitLineClamp: '1',
minHeight: '1rem',
fontWeight: 500,
letterSpacing: '-0.025em',
})
const alertDescriptionStyles = css({
gridColumnStart: '2',
display: 'grid',
justifyItems: 'start',
gap: '0.25rem',
fontSize: '0.875rem',
lineHeight: 'calc(1.25 / 0.875)',
color: 'var(--muted-foreground)',
'& p': { lineHeight: 1.625 },
// shadcn: `*:data-[slot=alert-description]:text-destructive/90` on the destructive alert. Kept in
// this descriptor so it wins over the muted color regardless of cascade-layer order.
'[data-slot="alert"][data-variant="destructive"] > &': {
color: 'color-mix(in oklab, var(--destructive) 90%, transparent)',
},
})
export function Alert(handle: Handle<AlertProps>) {
return () => {
let { variant = 'default', mix, ...props } = handle.props
return (
<div
data-slot="alert"
data-variant={variant}
role="alert"
{...props}
mix={[base, variants[variant], mix]}
/>
)
}
}
export function AlertTitle(handle: Handle<Props<'div'>>) {
return () => {
let { mix, ...props } = handle.props
return <div data-slot="alert-title" {...props} mix={[alertTitleStyles, mix]} />
}
}
export function AlertDescription(handle: Handle<Props<'div'>>) {
return () => {
let { mix, ...props } = handle.props
return <div data-slot="alert-description" {...props} mix={[alertDescriptionStyles, mix]} />
}
}Update the import paths to match your project setup.
Usage
import { Alert, AlertDescription, AlertTitle } from '#app/ui/alert.tsx'
import { InfoIcon } from '#app/ui/icons.tsx'<Alert>
<InfoIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components and dependencies to your app using the cli.
</AlertDescription>
</Alert>Composition
Use the following composition to build an Alert. Place an icon as the first child to get the icon column:
Alert
├── Icon
├── AlertTitle
└── AlertDescriptionExamples
Destructive
Use variant="destructive" to create a destructive alert.
Error
Your session has expired. Please log in again.
import { Alert, AlertDescription, AlertTitle } from '#app/ui/alert.tsx'
import { AlertCircleIcon } from '#app/ui/icons.tsx'
export function AlertDestructive() {
return () => (
<Alert variant="destructive">import { Alert, AlertDescription, AlertTitle } from '#app/ui/alert.tsx'
import { AlertCircleIcon } from '#app/ui/icons.tsx'
export function AlertDestructive() {
return () => (
<Alert variant="destructive">
<AlertCircleIcon />
<AlertTitle>Error</AlertTitle>
<AlertDescription>Your session has expired. Please log in again.</AlertDescription>
</Alert>
)
}API Reference
Alert
Displays a callout for user attention. Renders a <div role="alert">.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "destructive" | "default" |
mix | MixValue | - |
AlertTitle
The title of the alert.
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |
AlertDescription
The description or content of the alert.
| Prop | Type | Default |
|---|---|---|
mix | MixValue | - |