Button

Buttons trigger actions or events. The Davis Button component provides semantic variants, multiple sizes, loading states, and full keyboard accessibility.


Installation

npm install @libretexts/davis-react

Basic Usage

import { Button } from '@libretexts/davis-react';

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

Variants

Buttons come in seven semantic variants to communicate different action types.

<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="tertiary">Tertiary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="warning">Warning</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="outline">Outline</Button>

When to use each variant:

  • Primary - Main call-to-action (e.g., "Save", "Submit", "Continue")
  • Secondary - Secondary actions (e.g., "Cancel", "Back")
  • Tertiary - Tertiary actions, less emphasis than secondary
  • Destructive - Irreversible destructive actions (e.g., "Delete", "Remove")
  • Warning - Caution actions (e.g., "Archive", "Suspend")
  • Ghost - Subtle actions, minimal visual weight
  • Outline - Alternative style with border emphasis

Sizes

Buttons are available in three sizes to match your design hierarchy.

<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

Full Width

Make buttons span the full width of their container.

<Button fullWidth>Full Width Button</Button>

Loading State

Show a spinner while async actions are in progress. Buttons are automatically disabled when loading.

import { Button } from '@libretexts/davis-react';
import { useState } from 'react';

export default function Example() {
  const [loading, setLoading] = useState(false);

  async function handleClick() {
    setLoading(true);
    await fetch('/api/save');
    setLoading(false);
  }

  return (
    <Button loading={loading} onClick={handleClick}>
      Save Changes
    </Button>
  );
}

With Icons

Add icons to buttons to enhance clarity and scannability.

import { Button } from '@libretexts/davis-react';

function SaveIcon() {
  return (
    <svg className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
      <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
    </svg>
  );
}

export default function Example() {
  return (
    <>
      <Button icon={<SaveIcon />} iconPosition="left">
        Save
      </Button>
      <Button icon={<SaveIcon />} iconPosition="right">
        Continue
      </Button>
    </>
  );
}

Render a button as a link element while maintaining button styling.

<Button as="a" href="/dashboard">
  Go to Dashboard
</Button>

Props

PropTypeDefaultDescription
variant'primary' | 'secondary' | 'tertiary' | 'destructive' | 'warning' | 'ghost' | 'outline''primary'Visual style variant
size'sm' | 'md' | 'lg''md'Button size
loadingbooleanfalseShow loading spinner and disable button
disabledbooleanfalseDisable button
fullWidthbooleanfalseMake button full width
iconReactNode-Icon element to display
iconPosition'left' | 'right''left'Position of icon
asElementType'button'Render as different element (e.g., 'a')

Accessibility

The Button component is built with accessibility in mind:

  • Uses semantic <button> element by default
  • Properly handles disabled and loading states
  • Loading state includes aria-busy="true"
  • Disabled state includes aria-disabled="true" and disabled attribute
  • Keyboard accessible (Space and Enter keys)
  • Focus visible with clear focus rings

Best practices:

  • Always provide descriptive button text
  • For icon-only buttons, use aria-label
  • Use appropriate variants to communicate action type
  • Don't nest interactive elements inside buttons