Bỏ qua đến nội dung

Cảnh báo

Một hộp chú thích hiển thị ngay trong biểu mẫu để thông báo lỗi, cảnh báo và xác nhận thành công — các ô có màu theo trạng thái, viền theo phong cách tân thô mộc và bóng đổ đậm.

import { CheckCircle2Icon, InfoIcon } from "lucide-react"

import {

Alert là một callout nội dòng: một icon, một tiêu đề, một đoạn mô tả và một hành động tùy chọn, được xếp trên lưới CSS. Đây là một div role="alert" không cần thư viện phụ thuộc nào — không có primitive bên dưới, giống nhau ở cả hai backend — tạo kiểu theo công thức neobrutalist: viền dày, bóng đổ đậm và kiểu chữ đậm, kèm một trục status để tô màu cho lỗi, thành công, cảnh báo và thông tin.

Nên dùng khi:

  • Lỗi form và lỗi request — nêu một lỗi kiểm tra dữ liệu hoặc một lệnh gọi API thất bại ngay bên cạnh thứ vừa hỏng.
  • Xác nhận thành công và trạng thái — “đã lưu cài đặt”, “bản dùng thử sắp hết hạn”, “đã nhận thanh toán”, tô màu theo prop status.
  • Callout kèm bước tiếp theo — một cảnh báo hoặc thông báo nâng cấp có mang nút AlertAction (“Bật”, “Hoàn tác”, “Nâng cấp”).

Cài đặt

pnpm dlx shadcn@latest add https://neobrutalism.com/r/base/alert.json
npx shadcn@latest add https://neobrutalism.com/r/base/alert.json
yarn dlx shadcn@latest add https://neobrutalism.com/r/base/alert.json
bunx --bun shadcn@latest add https://neobrutalism.com/r/base/alert.json

Sao chép và dán đoạn mã sau vào dự án của bạn.

components/ui/alert.tsx
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 }

Cập nhật các đường dẫn import cho khớp với cấu trúc dự án của bạn.

Cách dùng

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>

Kết hợp

Dùng cách kết hợp sau để dựng một Alert:

Alert
├── Icon
├── AlertTitle
├── AlertDescription
└── AlertAction

Ví dụ

Cơ bản

Một alert cơ bản với biểu tượng, tiêu đề và mô tả.

import { CheckCircle2Icon } from "lucide-react"

import {

Phá hủy

Dùng variant="destructive" để tạo một alert phá hủy.

import { AlertCircleIcon } from "lucide-react"

import {

Hành động

Dùng AlertAction để thêm một nút hoặc phần tử hành động khác vào alert.

import {
  Alert,
  AlertAction,

Màu tùy chỉnh

Bạn có thể tùy chỉnh màu của alert bằng cách thêm các lớp tùy chỉnh như bg-amber-50 dark:bg-amber-950 vào thành phần Alert.

import { AlertTriangleIcon } from "lucide-react"

import {

RTL

Để bật hỗ trợ RTL trong Neobrutalism, xem hướng dẫn cấu hình RTL.

"use client"

import * as React from "react"

Khả năng truy cập

Phần gốc của alert render role="alert", một live region assertive ngầm định: trình đọc màn hình đọc nội dung của nó ngay khoảnh khắc nó được chèn vào DOM. Thông báo chỉ phát khi phần tử được chèn động — một alert đã có sẵn lúc trang tải xong sẽ được đọc như văn bản thường, nên hãy render nó có điều kiện khi bạn muốn nó được đọc lên. role="alert" không bao giờ di chuyển focus; nếu người dùng buộc phải phản hồi trước khi tiếp tục, hãy dùng alert dialog thay thế, và hãy coi AlertAction là một lối tắt chứ không phải con đường duy nhất.

Tham chiếu API

Alert

Thành phần Alert hiển thị một thông báo nổi bật để thu hút sự chú ý của người dùng.

PropTypeDefault
variant"default" | "destructive""default"

AlertTitle

Thành phần AlertTitle hiển thị tiêu đề của alert.

PropTypeDefault
classNamestring-

AlertDescription

Thành phần AlertDescription hiển thị mô tả hoặc nội dung của alert.

PropTypeDefault
classNamestring-

AlertAction

Thành phần AlertAction hiển thị một phần tử hành động (như một nút) được định vị tuyệt đối ở góc trên bên phải của alert.

PropTypeDefault
classNamestring-