Button

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

Installation

pnpm dlx shadcn@latest add @lumi-ui/button

Basic Usage

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

Variants

Default

Outline

Secondary

Ghost

Destructive

Size

Rounded

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

With Icon

The spacing between the icon and the text is automatically adjusted based on the size of the button. You do not need any margin on the icon.

Cookbook

Rendering as another tag

Base UI uses the render prop to change the underlying DOM element while preserving accessibility and behavior. This replaces the asChild pattern found in Radix UI.

<Button render={<div />} nativeButton={false}>
  Button that can contain complex children
</Button>

Here's an example rendering a link that looks like a button.

import Link from "next/link"
import { Button } from "@/components/ui/button"
 
export function ButtonLink() {
  return (
    <Button render={<Link href="/login" />} nativeButton={false}>
      Login
    </Button>
  )
}

Loading State

The isLoading prop automatically disables the button and prevents interaction.

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:

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

API Reference

PropTypeDefaultDescription
variantdefault | destructive | outline | secondary | ghost | linkdefaultThe visual style of the button.
sizedefault | sm | lg | icon | icon-sm | icon-lgdefaultThe size of the button. icon-* variants are square.
isLoadingbooleanfalseSets the button to a visual loading state, disables interaction, but maintains keyboard focusability.
classNamestring-Strict string only. Function-based class names are disabled to ensure compatibility with Tailwind merge utilities.
renderReactElement-Replaces the underlying HTML element.
nativeButtonbooleantrueWhen false, the button will be rendered as another tag.
focusableWhenDisabledbooleanfalseWhether the button should be focusable when disabled.

Migration Example

button-demo.tsx
import Link from "next/link"
import {
  Button,
} from "@/components/ui/button"
 
function ButtonDemo() {
  return (
    <Button asChild>
      <Link href="/login">Login</Link>
    </Button>
  );
}