پرش به محتوا

دکمه

یک ماشه قابل کلیک برای ارسال فرم‌ها، نوار ابزارها و تأییدهای مخرب — با حاشیه‌های ضخیم و سایه‌ای که هنگام کلیک روی آن فرو می‌رود.

import { ArrowUpIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

دکمه یک اقدام را اجرا می‌کند — submit، تأیید، حذف. بر پایهٔ Base UI Button ساخته شده و با دستور پخت نئوبروتالیستی استایل شده: حاشیه‌های ضخیم، سایهٔ offset سخت، و فشردن فعال که دکمه را داخل سایه هل می‌دهد.

برای این موارد از آن استفاده کنید:

  • ارسال فرم و CTA اصلیdefault اقدام اصلی را حمل می‌کند؛ secondary و outline برای بقیه.
  • نوار ابزار و اقدام آیکونی — اندازه‌های icon دکمه‌های مربعی می‌سازند؛ ButtonGroup آن‌ها را در ردیف segmented می‌چیند.
  • تأیید مخربdestructive برای حذف و برداشتن، معمولاً پشت یک دیالوگ.

نصب

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

وابستگی‌های زیر را نصب کنید:

pnpm add @base-ui/react
npm install @base-ui/react
yarn add @base-ui/react
bun add @base-ui/react

کد زیر را کپی کنید و در پروژهٔ خود بچسبانید.

components/ui/button.tsx
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { Slot } from "radix-ui"

import { cn } from "@/lib/utils"

const buttonVariants = cva(
  cn(
    "group/button font-head font-medium inline-flex cursor-pointer items-center justify-center gap-2 rounded whitespace-nowrap select-none transition-all duration-200",
    "disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-60",
    "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary aria-invalid:border-destructive",
    // Icons keep their own size; we only set a default when none is given so
    // Neobrutalism's h-4/size-4 icons aren't overridden.
    "[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
  ),
  {
    variants: {
      variant: {
        default:
          "border-2 border-black bg-primary text-primary-foreground shadow-md transition duration-200 hover:-translate-x-0.5 hover:-translate-y-0.5 hover:bg-primary-hover hover:shadow-lg active:translate-x-1 active:translate-y-1 active:shadow-none",
        secondary:
          "border-2 border-black bg-secondary text-secondary-foreground shadow-md transition duration-200 hover:-translate-x-0.5 hover:-translate-y-0.5 hover:bg-secondary-hover hover:shadow-lg active:translate-x-1 active:translate-y-1 active:shadow-none",
        destructive:
          "border-2 border-black bg-destructive text-destructive-foreground shadow-md transition duration-200 hover:-translate-x-0.5 hover:-translate-y-0.5 hover:bg-destructive/90 hover:shadow-lg active:translate-x-1 active:translate-y-1 active:shadow-none",
        outline:
          "border-2 bg-transparent shadow-md transition duration-200 hover:-translate-x-0.5 hover:-translate-y-0.5 hover:shadow-lg active:translate-x-1 active:translate-y-1 active:shadow-none",
        ghost: "bg-transparent hover:bg-accent",
        link: "bg-transparent hover:underline",
      },
      size: {
        default: "px-4 py-1.5 text-base",
        xs: "px-2 py-0.5 text-xs",
        sm: "px-3 py-1 text-sm",
        lg: "px-6 py-2 text-base lg:px-8 lg:py-3 lg:text-lg",
        icon: "p-2",
        "icon-xs": "p-1",
        "icon-sm": "p-1.5",
        "icon-lg": "p-3",
      },
    },
    defaultVariants: {
      variant: "default",
      size: "default",
    },
  }
)

function Button({
  className,
  variant = "default",
  size = "default",
  asChild = false,
  ...props
}: React.ComponentProps<"button"> &
  VariantProps<typeof buttonVariants> & {
    asChild?: boolean
  }) {
  const Comp = asChild ? Slot.Root : "button"

  return (
    <Comp
      data-slot="button"
      data-variant={variant}
      data-size={size}
      className={cn(buttonVariants({ variant, size, className }))}
      {...props}
    />
  )
}

export { Button, buttonVariants }

مسیرهای import را متناسب با ساختار پروژهٔ خود به‌روزرسانی کنید.

استفاده

import { Button } from "@/components/ui/button"
<Button variant="outline">Button</Button>

نشانگر

Tailwind v4 برای کامپوننت دکمه از cursor: pointer به cursor: default تغییر داد.

اگر می‌خواهید رفتار cursor: pointer را حفظ کنید، کد زیر را به فایل CSS خود اضافه کنید:

همچنین می‌توانید این را هنگام راه‌اندازی پروژه با npx shadcn@latest init --pointer فعال کنید.

globals.css
@layer base {
  button:not(:disabled),
  [role="button"]:not(:disabled) {
    cursor: pointer;
  }
}

نمونه‌ها

اندازه

از پراپ size برای تغییر اندازهٔ دکمه استفاده کنید.

import { ArrowUpRightIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

Default

import { Button } from "@/components/ui/button"

export function ButtonDefault() {

Outline

import { Button } from "@/components/ui/button"

export function ButtonOutline() {

Secondary

import { Button } from "@/components/ui/button"

export function ButtonSecondary() {

Ghost

import { Button } from "@/components/ui/button"

export function ButtonGhost() {

Destructive

import { Button } from "@/components/ui/button"

export function ButtonDestructive() {
import { Button } from "@/components/ui/button"

export function ButtonLink() {

Icon

import { CircleFadingArrowUpIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

با آیکون

فراموش نکنید که سمت data-icon="inline-start" یا data-icon="inline-end" را برای فاصله‌گذاری درست به آیکون اضافه کنید.

import { IconGitBranch, IconGitFork } from "@tabler/icons-react"

import { Button } from "@/components/ui/button"

گرد

از کلاس rounded-full برای گرد کردن دکمه استفاده کنید.

import { ArrowUpIcon } from "lucide-react"

import { Button } from "@/components/ui/button"

Spinner

یک کامپوننت <Spinner /> داخل دکمه رندر کنید تا حالت بارگذاری را نشان دهید. فراموش نکنید که سمت data-icon="inline-start" یا data-icon="inline-end" را برای فاصله‌گذاری درست به اسپینر اضافه کنید.

import { Button } from "@/components/ui/button"
import { Spinner } from "@/components/ui/spinner"

Button Group

برای ساخت یک گروه دکمه، از کامپوننت ButtonGroup استفاده کنید. برای جزئیات بیشتر مستندات Button Group را ببینید.

"use client"

import * as React from "react"

به‌عنوان پیوند

می‌توانید از دالهٔ کمکی buttonVariants استفاده کنید تا یک پیوند شبیه دکمه به نظر برسد.

برای پیوندها از <Button render={<a />} nativeButton={false} /> استفاده نکنید. کامپوننت Button از Base UI همیشه role="button" را اعمال می‌کند، که نقش معنایی پیوند را روی عناصر <a> بازنویسی می‌کند. در عوض از buttonVariants با یک تگ سادهٔ <a> استفاده کنید.

import { buttonVariants } from "@/components/ui/button"

export function ButtonRender() {

RTL

برای فعال‌سازی پشتیبانی RTL در Neobrutalism، راهنمای پیکربندی RTL را ببینید.

"use client"

import { ArrowRightIcon, PlusIcon } from "lucide-react"

دسترسی‌پذیری

دکمه از الگوی WAI-ARIA Button پیروی می‌کند. به‌صورت پیش‌فرض یک <button> بومی رندر می‌کند؛ وقتی render عنصر دیگری می‌گذارد، Base UI مقادیر role="button"، tabindex و فعال‌سازی صفحه‌کلید را سیم می‌کند تا جایگزین برای فناوری کمکی مثل دکمهٔ واقعی رفتار کند (نکتهٔ As Link بالا را برای تنها موردی که آن role اشتباه است ببینید).

تعاملات صفحه‌کلید:

کلیدعمل
Tab / Shift + Tabانتقال فوکوس به / از دکمه
Space / Enterفعال‌سازی دکمه

مرجع API

Button

کامپوننت Button یک پوشش دور عنصر button است که مجموعهٔ متنوعی از استایل‌ها و کارکردها را اضافه می‌کند.

PropTypeDefault
variant"default" | "outline" | "ghost" | "destructive" | "secondary" | "link""default"
size"default" | "xs" | "sm" | "lg" | "icon" | "icon-xs" | "icon-sm" | "icon-lg""default"