We use tracking cookies to understand how you use the product and help us improve it. For more information on how we store cookies, read our  privacy policy.

Button.tsx

Versatile button component with multiple variants and sizes

The Button component is a flexible, accessible button built with Radix UI Slot and class-variance-authority for variant management.

Features

  • Multiple visual variants (default, destructive, outline, secondary, ghost, link)
  • Size options (sm, default, lg, icon)
  • Polymorphic with asChild prop
  • Full TypeScript support
  • Accessible with keyboard navigation

Basic Usage

app/page.tsx
import { Button } from '@/components/ui/Button';

export default function Page() {
  return <Button>Click me</Button>;
}

Variants

Default

Primary brand-colored button:

app/page.tsx
<Button variant="default">Default Button</Button>

Destructive

For dangerous actions:

app/page.tsx
<Button variant="destructive">Delete Account</Button>

Outline

Bordered button with transparent background:

app/page.tsx
<Button variant="outline">Outline Button</Button>

Secondary

Neutral-colored button:

app/page.tsx
<Button variant="secondary">Secondary Button</Button>

Ghost

Minimal button with hover effect:

app/page.tsx
<Button variant="ghost">Ghost Button</Button>

Text button with underline on hover:

app/page.tsx
<Button variant="link">Link Button</Button>

Sizes

app/page.tsx
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>
<Button size="icon">
  <Icon />
</Button>

As Child (Polymorphic)

Render as a different element while keeping button styles:

app/page.tsx
import Link from 'next/link';
import { Button } from '@/components/ui/Button';

<Button asChild>
  <Link href="/dashboard">Go to Dashboard</Link>
</Button>

With Icons

app/page.tsx
import { ArrowRight } from 'lucide-react';
import { Button } from '@/components/ui/Button';

<Button>
  Continue
  <ArrowRight className="ml-2 h-4 w-4" />
</Button>

Disabled State

app/page.tsx
<Button disabled>Disabled Button</Button>

Loading State

app/page.tsx
import { Loader2 } from 'lucide-react';

<Button disabled>
  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
  Loading...
</Button>

Implementation

The Button uses class-variance-authority for variant management:

components/ui/Button.tsx
const buttonVariants = cva(
  'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors',
  {
    variants: {
      variant: {
        default: 'bg-brand text-brand-foreground hover:bg-brand/90',
        outline: 'border border-neutral-border hover:bg-accent',
      },
      size: {
        default: 'h-9 px-4 py-2',
        sm: 'h-8 px-3 text-xs',
        lg: 'h-10 px-8',
        icon: 'h-9 w-9',
      },
    },
    defaultVariants: {
      variant: 'default',
      size: 'default',
    },
  }
);

Props

The Button extends standard HTML button attributes and adds:

  • variant: Visual style variant
  • size: Button size
  • asChild: Render as child element (polymorphic)
  • className: Additional CSS classes

Accessibility

  • Keyboard accessible (Enter/Space to activate)
  • Focus visible styles
  • Disabled state prevents interaction
  • Proper ARIA attributes when used with icons

How is this guide ?

Last updated on