Skip to main content

Overview

The Button component provides an accessible, customizable button with support for multiple variants, sizes, and icons. It’s built on React Aria Components for full keyboard navigation and screen reader support.

Import

import { Button } from 'stride-ds';

Basic Usage

import { Button } from 'stride-ds';

function Example() {
  return <Button>Click me</Button>;
}

Variants

The Button component supports four visual variants:

Primary

The default variant for primary actions.
<Button variant="primary">Primary Button</Button>

Secondary

For secondary actions with a subtle appearance.
<Button variant="secondary">Secondary Button</Button>

Ghost

For tertiary actions with minimal styling.
<Button variant="ghost">Ghost Button</Button>

Destructive

For dangerous or destructive actions.
<Button variant="destructive">Delete Account</Button>

Sizes

Three size options are available:
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

With Icons

Left Icon

import { Download } from 'lucide-react';

<Button leftIcon={<Download size={16} />}>
  Download
</Button>

Right Icon

import { ArrowRight } from 'lucide-react';

<Button rightIcon={<ArrowRight size={16} />}>
  Continue
</Button>

Both Icons

import { Star, ArrowRight } from 'lucide-react';

<Button 
  leftIcon={<Star size={16} />}
  rightIcon={<ArrowRight size={16} />}
>
  Favorite
</Button>

States

Disabled

<Button isDisabled>Disabled Button</Button>

Loading State

Combine with a loading icon for async operations:
import { Loader2 } from 'lucide-react';

<Button 
  isDisabled={isLoading}
  leftIcon={isLoading ? <Loader2 className="animate-spin" size={16} /> : null}
>
  {isLoading ? 'Loading...' : 'Submit'}
</Button>

Props

variant
'primary' | 'secondary' | 'ghost' | 'destructive'
default:"'primary'"
Visual style variant of the button.
size
'sm' | 'md' | 'lg'
default:"'md'"
Size of the button. Affects height, padding, and font size.
leftIcon
React.ReactNode
Icon to display on the left side of the button text.
rightIcon
React.ReactNode
Icon to display on the right side of the button text.
isDisabled
boolean
default:"false"
Whether the button is disabled. When disabled, the button cannot be pressed and shows reduced opacity.
onPress
(e: PressEvent) => void
Handler called when the button is pressed.
onPressStart
(e: PressEvent) => void
Handler called when a press interaction starts.
onPressEnd
(e: PressEvent) => void
Handler called when a press interaction ends.
className
string
Additional CSS classes to apply to the button.
children
React.ReactNode
The content to display inside the button.
type
'button' | 'submit' | 'reset'
default:"'button'"
The button type (for form submission).

Accessibility

The Button component is built with React Aria Components and provides:
  • Keyboard Navigation: Fully accessible via keyboard (Space/Enter to activate)
  • Focus Management: Clear focus indicators that respect the design system
  • Screen Reader Support: Proper ARIA attributes and roles
  • Disabled State: Properly communicated to assistive technologies

Best Practices

  1. Always provide meaningful text content or aria-label for icon-only buttons:
    <Button aria-label="Close dialog">
      <X size={16} />
    </Button>
    
  2. Use appropriate variants for context:
    • primary for main actions
    • secondary for alternative actions
    • ghost for tertiary actions
    • destructive for dangerous operations
  3. Provide visual feedback for loading states when performing async operations

Examples

All Variants

<div className="flex gap-4">
  <Button variant="primary">Primary</Button>
  <Button variant="secondary">Secondary</Button>
  <Button variant="ghost">Ghost</Button>
  <Button variant="destructive">Destructive</Button>
</div>

All Sizes with Icons

import { Download } from 'lucide-react';

<div className="flex gap-4 items-center">
  <Button size="sm" leftIcon={<Download size={14} />}>
    Small
  </Button>
  <Button size="md" leftIcon={<Download size={16} />}>
    Medium
  </Button>
  <Button size="lg" leftIcon={<Download size={18} />}>
    Large
  </Button>
</div>

Form Submit Button

function MyForm() {
  const [isSubmitting, setIsSubmitting] = useState(false);

  return (
    <form onSubmit={handleSubmit}>
      {/* form fields */}
      <Button 
        type="submit" 
        isDisabled={isSubmitting}
        leftIcon={isSubmitting ? <Loader2 className="animate-spin" size={16} /> : null}
      >
        {isSubmitting ? 'Submitting...' : 'Submit Form'}
      </Button>
    </form>
  );
}

Build docs developers (and LLMs) love