import { CheckCircle2Icon, InfoIcon } from "lucide-react"
import {얼럿은 인라인 콜아웃입니다. 아이콘, 제목, 설명, 그리고 선택적인 액션을 CSS 그리드에 배치합니다. 아래에 깔린 프리미티브 없이 의존성 없는 role="alert" div로 동작하므로 두 백엔드에서 완전히 동일합니다. 네오브루탈리즘 공식(두꺼운 테두리, 선명한 그림자, 굵은 서체)에 맞춰 스타일을 입혔습니다. 여기에 status 축으로 오류, 성공, 경고, 정보 색상을 지정합니다.
다음과 같은 경우에 사용합니다.
- 폼과 요청 오류 — 유효성 검사 실패나 실패한 API 호출을 문제가 생긴 지점 바로 옆에 드러냅니다.
- 성공 및 상태 확인 — "설정이 저장되었습니다", "체험판이 곧 만료됩니다", "결제가 완료되었습니다" 같은 메시지를
statusprop으로 색까지 맞춰 보여 줍니다. - 후속 동작이 딸린 콜아웃 — "활성화", "실행 취소", "업그레이드" 같은
AlertAction버튼을 함께 두는 경고나 업그레이드 안내.
설치#
pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/alert.jsonnpx shadcn@latest add https://neobrutalism.com/r/base/alert.jsonyarn dlx shadcn@latest add https://neobrutalism.com/r/base/alert.jsonbunx --bun shadcn@latest add https://neobrutalism.com/r/base/alert.json
다음 코드를 복사해 프로젝트에 붙여넣습니다.
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
// CSS-grid layout (shadcn-style): drop an icon as a direct child and the alert
// auto-arranges into an icon column + a content column — no manual flex wrapper.
// `has-[>svg]` adds the icon column only when an icon is present. NeoBrutalist
// chrome: hard 2px border, square corners, hard offset shadow.
const alertVariants = cva(
cn(
"group/alert relative grid w-full grid-cols-[0_1fr] items-start gap-y-1 rounded border-2 px-4 py-3 text-left text-sm shadow-md",
"has-[>svg]:grid-cols-[1.25rem_1fr] has-[>svg]:gap-x-3",
"has-data-[slot=alert-action]:pr-14",
"[&>svg]:size-5 [&>svg]:translate-y-0.5 [&>svg]:shrink-0 [&>svg]:text-current"
),
{
variants: {
// shadcn's variant axis (kept for API compatibility). `solid` is a Neobrutalism
// addition.
variant: {
default:
"border-border bg-background text-foreground *:data-[slot=alert-description]:text-muted-foreground",
destructive:
"border-red-900 bg-red-300 text-red-900 *:data-[slot=alert-description]:text-red-900/80",
solid:
"border-border bg-foreground text-background *:data-[slot=alert-description]:text-background/80",
},
// Neobrutalism status axis — additive; overrides the variant's colors when set.
status: {
error:
"border-red-900 bg-red-300 text-red-900 *:data-[slot=alert-description]:text-red-900/80",
success:
"border-green-900 bg-green-300 text-green-900 *:data-[slot=alert-description]:text-green-900/80",
warning:
"border-yellow-900 bg-yellow-300 text-yellow-900 *:data-[slot=alert-description]:text-yellow-900/80",
info: "border-blue-900 bg-blue-300 text-blue-900 *:data-[slot=alert-description]:text-blue-900/80",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Alert({
className,
variant,
status,
...props
}: React.ComponentProps<"div"> & VariantProps<typeof alertVariants>) {
return (
<div
data-slot="alert"
role="alert"
className={cn(alertVariants({ variant, status }), className)}
{...props}
/>
)
}
function AlertTitle({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-title"
className={cn(
"col-start-2 min-h-5 font-head text-base leading-tight tracking-tight [&_a]:underline [&_a]:underline-offset-3",
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-1 text-sm [&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-foreground [&_p]:leading-relaxed [&_p:not(:last-child)]:mb-4",
className
)}
{...props}
/>
)
}
function AlertAction({ className, ...props }: React.ComponentProps<"div">) {
return (
<div
data-slot="alert-action"
className={cn("absolute top-2 right-2", className)}
{...props}
/>
)
}
export { Alert, AlertTitle, AlertDescription, AlertAction, alertVariants }
프로젝트 설정에 맞게 import 경로를 업데이트합니다.
사용법#
import {
Alert,
AlertAction,
AlertDescription,
AlertTitle,
} from "@/components/ui/alert"<Alert>
<InfoIcon />
<AlertTitle>Heads up!</AlertTitle>
<AlertDescription>
You can add components and dependencies to your app using the cli.
</AlertDescription>
<AlertAction>
<Button variant="outline">Enable</Button>
</AlertAction>
</Alert>구성#
Alert를 만들려면 다음 구성을 사용합니다:
Alert
├── Icon
├── AlertTitle
├── AlertDescription
└── AlertAction예제#
기본#
아이콘, 제목, 설명을 갖춘 기본적인 알림입니다.
import { CheckCircle2Icon } from "lucide-react"
import {파괴적#
variant="destructive"를 사용해 파괴적인 알림을 만듭니다.
import { AlertCircleIcon } from "lucide-react"
import {액션#
AlertAction을 사용해 버튼이나 다른 액션 요소를 알림에 추가합니다.
import {
Alert,
AlertAction,커스텀 색상#
Alert 컴포넌트에 bg-amber-50 dark:bg-amber-950 같은 커스텀 클래스를 추가하여 알림 색상을 커스터마이즈할 수 있습니다.
import { AlertTriangleIcon } from "lucide-react"
import {RTL#
Neobrutalism에서 RTL을 활성화하는 방법은 RTL 설정 가이드를 참조하세요.
"use client"
import * as React from "react"접근성#
얼럿 루트는 role="alert"로 렌더링됩니다. 암묵적인 assertive 라이브 리전이므로, 스크린 리더는 해당 콘텐츠가 DOM에 삽입되는 순간 그 내용을 읽습니다. 이 안내는 동적으로 삽입될 때만 발생합니다. 페이지가 로드될 때부터 이미 존재한 얼럿은 일반 텍스트로 읽히므로, 반드시 들려야 하는 내용이라면 조건부로 렌더링하세요. role="alert"는 포커스를 옮기지 않습니다. 사용자가 계속 진행하기 전에 반드시 응답해야 한다면 얼럿 다이얼로그를 사용하고, AlertAction은 유일한 진행 경로가 아니라 단축 수단으로 다루세요.
API 참조#
Alert#
Alert 컴포넌트는 사용자의 주의를 끄는 콜아웃을 표시합니다.
| Prop | Type | Default |
|---|---|---|
variant | "default" | "destructive" | "default" |
AlertTitle#
AlertTitle 컴포넌트는 알림의 제목을 표시합니다.
| Prop | Type | Default |
|---|---|---|
className | string | - |
AlertDescription#
AlertDescription 컴포넌트는 알림의 설명이나 내용을 표시합니다.
| Prop | Type | Default |
|---|---|---|
className | string | - |
AlertAction#
AlertAction 컴포넌트는 알림의 오른쪽 위 모서리에 절대 배치되는 액션 요소(예: 버튼)를 표시합니다.
| Prop | Type | Default |
|---|---|---|
className | string | - |