Buttons & Actions

Interactive button components and action triggers.

Use Button from @kit/ui/button with variants (default, secondary, outline, ghost, destructive, link) and sizes (xs, sm, default, lg, icon). For loading states, disable the button and show a Spinner. Use the render prop to make buttons act as links.

This guide is part of the UI Components documentation.

Definition: Button components are interactive elements that trigger actions, with built-in support for variants, sizes, disabled states, and composition with other elements via the Base UI render prop pattern.

Button

Primary button component with variants and sizes.

import { Button } from '@kit/ui/button';

Variants

<Button variant="default">Default</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="link">Link</Button>

Sizes

<Button size="xs">Extra Small</Button>
<Button size="sm">Small</Button>
<Button size="default">Default</Button>
<Button size="lg">Large</Button>

Icon Buttons

import { Plus, Settings } from 'lucide-react';
<Button size="icon">
<Plus className="h-4 w-4" />
</Button>
<Button size="icon-sm">
<Settings className="h-4 w-4" />
</Button>
<Button size="icon-xs">
<Plus className="h-3 w-3" />
</Button>

Loading State

import { Spinner } from '@kit/ui/spinner';
<Button disabled={isPending}>
{isPending ? (
<>
<Spinner className="mr-2 h-4 w-4" />
Loading...
</>
) : (
'Submit'
)}
</Button>

Uses the render prop pattern from Base UI:

import Link from 'next/link';
<Button render={<Link href="/dashboard" />}>
Go to Dashboard
</Button>

Button Group

Group related buttons together.

import { ButtonGroup } from '@kit/ui/button-group';
<ButtonGroup>
<Button variant="outline">Left</Button>
<Button variant="outline">Center</Button>
<Button variant="outline">Right</Button>
</ButtonGroup>

Vertical Orientation

<ButtonGroup orientation="vertical">
<Button variant="outline">Top</Button>
<Button variant="outline">Middle</Button>
<Button variant="outline">Bottom</Button>
</ButtonGroup>

Card Button

Clickable card component for selection interfaces.

import { CardButton, CardButtonHeader, CardButtonTitle, CardButtonContent, CardButtonFooter } from '@kit/ui/card-button';
<CardButton onClick={handleClick}>
<CardButtonHeader>
<CardButtonTitle>Option Title</CardButtonTitle>
</CardButtonHeader>
<CardButtonContent>
<span className="text-muted-foreground text-sm">
Description of this option
</span>
</CardButtonContent>
</CardButton>

Without Arrow

<CardButton>
<CardButtonHeader displayArrow={false}>
<CardButtonTitle>Simple Card</CardButtonTitle>
</CardButtonHeader>
<CardButtonContent>
Content without arrow indicator
</CardButtonContent>
</CardButton>

Copy to Clipboard

Button that copies text to clipboard with toast feedback.

import { CopyToClipboard } from '@kit/ui/copy-to-clipboard';
<CopyToClipboard value="text-to-copy">
Copy this text
</CopyToClipboard>
{/* Custom messages */}
<CopyToClipboard
value={apiKey}
successMessage="API key copied!"
errorMessage="Failed to copy API key"
>
{apiKey}
</CopyToClipboard>

Shows a copy icon that changes to a checkmark on success, with toast notification.

Common Pitfalls

  • Not disabling during loading: Always set disabled={isPending} when showing a loading state to prevent double submissions.
  • Wrong Link integration: Use render={<Link href="..." />} pattern, not wrapping Button with Link.
  • Missing icon sizing: Icons in buttons need explicit sizing: <Plus className="h-4 w-4" />.
  • ButtonGroup spacing: Don't add gap classes to ButtonGroup - it handles spacing internally.
  • Destructive without confirmation: Always pair variant="destructive" with a confirmation dialog for irreversible actions.

Frequently Asked Questions

How do I make a button look like a link?
Use variant='link'. For actual navigation, combine with the render prop: <Button variant='link' render={<Link href='...' />}>
What's the difference between ghost and outline?
Ghost has no border and only shows background on hover. Outline has a visible border and changes background on hover.
How do I add an icon to a button?
Import from lucide-react and place inside the button: <Button><Plus className='h-4 w-4 mr-2' />Add Item</Button>
Can I use buttons in Server Components?
Static buttons (without onClick) work in Server Components. Buttons with event handlers need 'use client'.
How do I show loading state during form submission?
Use useTransition or form pending state: disable the button and conditionally render Spinner when isPending is true.

Next: Layout & Structure →