← Back to home

Button

A polymorphic button component with support for loading states, icons, and composition.

Usage

tsx
import { Button } from '@components-kit/react';

// Basic button
<Button variantName="primary">Submit</Button>

// With icons
<Button leadingIcon={<SearchIcon />} variantName="secondary">
  Search
</Button>

// Loading state
<Button isLoading variantName="primary">
  Saving...
</Button>

// Full-width call-to-action
<Button fullWidth variantName="primary">
  Continue
</Button>

// Disabled button
<Button disabled variantName="secondary">
  Unavailable
</Button>

// Icon-only button (requires aria-label)
<Button aria-label="Search" leadingIcon={<SearchIcon />} variantName="ghost" />

// Polymorphic - render as link
<Button as="a" href="/home" variantName="outline">
  Go Home
</Button>

// Composition with asChild
<Button asChild variantName="primary">
  <a href="/dashboard">Dashboard</a>
</Button>

Props

PropTypeDefaultDescription
asElementType"button"HTML element to render as (polymorphic)
asChildbooleanfalseMerge props with child element
size"sm" | "md" | "lg""md"Size of the button
variantNameVariantFor<"button">-Variant name for styling
isLoadingbooleanfalseShows loading state, disables button
disabledboolean-Disables the button
fullWidthboolean-Makes button full width
leadingIconReactNode-Icon before button text
trailingIconReactNode-Icon after button text

Also accepts all standard button HTML attributes.

Data Attributes

AttributeValuesDescription
data-variantstringThe variant name for styling
data-size"sm", "md", "lg"The size variant
data-loadingtruePresent when loading
data-disabledtruePresent when disabled
data-full-widthtruePresent when full width

Accessibility

  • Uses semantic <button> element for proper keyboard navigation
  • Uses aria-disabled instead of native disabled to keep button focusable
  • Sets aria-busy="true" during loading for screen reader announcement
  • Prevents interactions when disabled via event handlers

Icon-Only Buttons

When using only an icon without visible text, you must provide aria-label:

tsx
<Button aria-label="Close dialog" leadingIcon={<CloseIcon />} />

Best Practices

  • Use type="button" for non-submit buttons (the default)
  • Provide loading feedback text when appropriate
  • Ensure sufficient color contrast
  • Keep button labels concise and action-oriented