cortexcn

Button

Displays a button or a component that looks like a button.

Loading…
import { ArrowUpIcon } from "lucide-react";import { Button } from "@/components/ui/button";export default function ButtonDemo() {  return (    <div className="flex flex-wrap items-center gap-2 md:flex-row">      <Button variant="outline">Button</Button>      <Button variant="outline" size="icon" aria-label="Submit">        <ArrowUpIcon />      </Button>    </div>  );}

Installation

npx shadcn@latest add @cortexcn/button
Install the following dependencies:
npm install radix-ui class-variance-authority
Copy and paste the following code into your project.
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(  "group/button inline-flex shrink-0 cursor-pointer items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:scale-[0.98] disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",  {    variants: {      variant: {        default: "bg-primary text-primary-foreground hover:bg-primary/80",        outline:          "border-border bg-background shadow-xs hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50",        secondary:          "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",        ghost:          "hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",        destructive:          "bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",        link: "text-primary decoration-1 underline-offset-3 hover:underline active:scale-none",      },      size: {        default:          "h-9 gap-1.5 px-2.5 in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",        xs: "h-6 gap-1 rounded-[min(var(--radius-lg),8px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3",        sm: "h-8 gap-1 rounded-[min(var(--radius-lg),10px)] px-2.5 in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5",        lg: "h-10 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",        icon: "size-9",        "icon-xs":          "size-6 rounded-[min(var(--radius-lg),8px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3",        "icon-sm":          "size-8 rounded-[min(var(--radius-lg),10px)] in-data-[slot=button-group]:rounded-lg",        "icon-lg": "size-10",      },    },    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 };
Update the import paths to match your project setup.

Usage

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

Cursor

Tailwind v4 switched from cursor: pointer to cursor: default for the button component.

If you want to keep the cursor: pointer behavior, add the following code to your CSS file:

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

Examples

Size

Use the size prop to change the size of the button.

Loading…
import { ArrowUpRightIcon } from "lucide-react";import { Button } from "@/components/ui/button";export default function ButtonSize() {  return (    <div className="flex flex-col items-start gap-8 sm:flex-row">      <div className="flex items-start gap-2">        <Button size="xs" variant="outline">          Extra Small        </Button>        <Button size="icon-xs" aria-label="Submit" variant="outline">          <ArrowUpRightIcon />        </Button>      </div>      <div className="flex items-start gap-2">        <Button size="sm" variant="outline">          Small        </Button>        <Button size="icon-sm" aria-label="Submit" variant="outline">          <ArrowUpRightIcon />        </Button>      </div>      <div className="flex items-start gap-2">        <Button variant="outline">Default</Button>        <Button size="icon" aria-label="Submit" variant="outline">          <ArrowUpRightIcon />        </Button>      </div>      <div className="flex items-start gap-2">        <Button variant="outline" size="lg">          Large        </Button>        <Button size="icon-lg" aria-label="Submit" variant="outline">          <ArrowUpRightIcon />        </Button>      </div>    </div>  );}

Default

Loading…
import { Button } from "@/components/ui/button";export default function ButtonDefault() {  return <Button>Button</Button>;}

Outline

Loading…
import { Button } from "@/components/ui/button";export default function ButtonOutline() {  return <Button variant="outline">Outline</Button>;}

Secondary

Loading…
import { Button } from "@/components/ui/button";export default function ButtonSecondary() {  return <Button variant="secondary">Secondary</Button>;}

Ghost

Loading…
import { Button } from "@/components/ui/button";export default function ButtonGhost() {  return <Button variant="ghost">Ghost</Button>;}

Destructive

Loading…
import { Button } from "@/components/ui/button";export default function ButtonDestructive() {  return <Button variant="destructive">Destructive</Button>;}
Loading…
import { Button } from "@/components/ui/button";export default function ButtonLink() {  return <Button variant="link">Link</Button>;}

Icon

Loading…
import { CircleFadingArrowUpIcon } from "lucide-react";import { Button } from "@/components/ui/button";export default function ButtonIcon() {  return (    <Button variant="outline" size="icon">      <CircleFadingArrowUpIcon />    </Button>  );}

With Icon

Remember to add the data-icon="inline-start" or data-icon="inline-end" attribute to the icon for the correct spacing.

Loading…
import { GitBranchIcon } from "lucide-react";import { Button } from "@/components/ui/button";export default function ButtonWithIcon() {  return (    <Button variant="outline" size="sm">      <GitBranchIcon data-icon="inline-start" /> New Branch    </Button>  );}

Rounded

Use the rounded-full class to make the button rounded.

Loading…
import { ArrowUpIcon } from "lucide-react";import { Button } from "@/components/ui/button";export default function ButtonRounded() {  return (    <div className="flex flex-col gap-8">      <Button variant="outline" size="icon" className="rounded-full">        <ArrowUpIcon />      </Button>    </div>  );}

Spinner

Render a <Spinner /> component inside the button to show a loading state. Remember to add the data-icon="inline-start" or data-icon="inline-end" attribute to the spinner for the correct spacing.

Loading…
import { Button } from "@/components/ui/button";import { Spinner } from "@/components/ui/spinner";export default function ButtonSpinner() {  return (    <div className="flex gap-2">      <Button variant="outline" disabled>        <Spinner data-icon="inline-start" />        Generating      </Button>      <Button variant="secondary" disabled>        Downloading        <Spinner data-icon="inline-start" />      </Button>    </div>  );}

Button Group

To create a button group, use the ButtonGroup component.

Loading…
import { PlusIcon } from "lucide-react";import { Button } from "@/components/ui/button";import { ButtonGroup } from "@/components/ui/button-group";export default function ButtonGroupDemo() {  return (    <ButtonGroup>      <Button variant="outline">Archive</Button>      <Button variant="outline">Report</Button>      <Button variant="outline">Snooze</Button>      <Button variant="outline" size="icon" aria-label="Add">        <PlusIcon />      </Button>    </ButtonGroup>  );}

As Child

You can use the asChild prop on <Button /> to make another component look like a button. Here's an example of a link that looks like a button.

Loading…
import Link from "next/link";import { Button } from "@/components/ui/button";export default function ButtonAsChild() {  return (    <Button asChild>      <Link href="/login">Login</Link>    </Button>  );}

RTL

Buttons respect the document direction. Use the rtl: variant to flip directional icons.

Loading…
"use client";import * as React from "react";import { ArrowRightIcon, PlusIcon } from "lucide-react";import { Button } from "@/components/ui/button";import { Spinner } from "@/components/ui/spinner";const content = {  ltr: {    button: "Button",    delete: "Delete",    submit: "Submit",    loading: "Loading",  },  rtl: {    button: "زر",    delete: "حذف",    submit: "إرسال",    loading: "جاري التحميل",  },} as const;export default function ButtonRtl() {  const [dir, setDir] = React.useState<"ltr" | "rtl">("rtl");  const t = content[dir];  return (    <div className="flex flex-col items-center gap-6">      <Button        variant="ghost"        size="sm"        onClick={() => setDir((d) => (d === "rtl" ? "ltr" : "rtl"))}      >        Toggle dir ({dir})      </Button>      <div className="flex flex-wrap items-center gap-2 md:flex-row" dir={dir}>        <Button variant="outline">{t.button}</Button>        <Button variant="destructive">{t.delete}</Button>        <Button variant="outline">          {t.submit}{" "}          <ArrowRightIcon className="rtl:rotate-180" data-icon="inline-end" />        </Button>        <Button variant="outline" size="icon" aria-label="Add">          <PlusIcon />        </Button>        <Button variant="secondary" disabled>          <Spinner data-icon="inline-start" /> {t.loading}        </Button>      </div>    </div>  );}

API Reference

Button

The Button component is a wrapper around the button element that adds a variety of styles and functionality.

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

On this page