Skip to main content

button

A customizable button component for triggering actions in your application.

Features

  • Multiple styles, sizes, and border options out of the box
  • Built-in loading state with spinner and auto-disable
  • Supports icons, dual icons, and collapsed icon-only mode
  • Flexible asChild rendering for links and custom wrappers
  • Smooth hover animations with optional AnimationIcon
  • Fully typed, accessible, and responsive
  • Powered by @gentleduck/variants for scalable theming
  • Clean, composable, and Tailwind-optimized

Philosophy

Buttons are the primary call to action in any interface. We ship an intentionally rich variant system because buttons carry the most visual weight in UI decisions — primary, destructive, ghost, and outline each communicate different levels of commitment. The asChild pattern lets you render any element as a button, because sometimes a link needs to look like one.

How It's Built

Loading diagram...

Installation


npx @gentleduck/cli add button

npx @gentleduck/cli add button

Usage

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

Button

Button is a versatile and customizable React component designed to render a button with various styles and functionalities. It supports different sizes, variants, and additional features like loading states and icons. The component is flexible and can be used in a variety of scenarios, from simple buttons to complex interactive elements.

Example Usage:

import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
 
const MyButton = () => {
  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <Button size="lg" variant="default">
          Submit
        </Button>
      </TooltipTrigger>
      <TooltipContent>Submit Button</TooltipContent>
    </Tooltip>
  )
}
import { Button } from '@/components/ui/button'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
 
const MyButton = () => {
  return (
    <Tooltip>
      <TooltipTrigger asChild>
        <Button size="lg" variant="default">
          Submit
        </Button>
      </TooltipTrigger>
      <TooltipContent>Submit Button</TooltipContent>
    </Tooltip>
  )
}

You can use the buttonVariants helper to create a any element like a link that looks like a button.

import { buttonVariants } from '@/components/ui/button'
import { buttonVariants } from '@/components/ui/button'
<Link className={buttonVariants({ variant: 'outline' })}>I'm a Link 🦆</Link>
<Link className={buttonVariants({ variant: 'outline' })}>I'm a Link 🦆</Link>

Alternatively, you can set the asChild parameter and nest the link component.

<Button asChild>
  <Link href="/tos">I'm a Link to ToS 🦆</Link>
</Button>
<Button asChild>
  <Link href="/tos">I'm a Link to ToS 🦆</Link>
</Button>

Examples

Primary

Secondary

Ghost

Outline

Destructive

Warning

Dashed

Nothing

With Border

With Border Destructive

With Border Warning

With Border Secondary

With Icon

Loading

When loading is true, Button renders a lucide-react <Loader /> with animate-spin, disables interaction, and replaces the leading icon until loading completes.

With Second Icon

Collapsible

Expand Icon

RTL

API Reference

Button Props

PropTypeDefaultDescription
variant'default' | 'destructive' | 'warning' | 'outline' | 'dashed' | 'secondary' | 'ghost' | 'link' | 'expand_icon' | 'nothing''default'Visual style variant
size'default' | 'sm' | 'lg' | 'icon' | 'icon-sm' | 'icon-lg''default'Size of the button
border'default' | 'primary' | 'secondary' | 'destructive' | 'warning''default'Border style variant
asChildboolean--If true, renders using a custom child element via Slot (e.g. a Link)
loadingboolean--If true, renders <Loader className="animate-spin" />, disables the button, and temporarily overrides icon
disabledboolean--Disables the button manually
iconReact.ReactNode--Primary icon displayed before the content (or centered if collapsed)
secondIconReact.ReactNode--Secondary icon displayed after the content
isCollapsedboolean--If true, renders icon-only button (hides children and secondIcon)
type'button' | 'submit' | 'reset''button'Native HTML button type
...propsOmit<React.HTMLProps<HTMLButtonElement>, 'size'>--Additional props to spread to the button element

AnimationIcon Props

PropTypeDefaultDescription
childrenReact.ReactNode(required)Content inside the animation icon wrapper
animationIcon{ icon?: React.ReactNode; iconPlacement?: 'left' | 'right' }--Animation icon configuration with icon element and placement direction