# Button

> Displays a button or a component that looks like a button, with multiple style variants and sizes

## Installation

```bash
pnpm add @wandercom/design-system-web
```

## Usage

```tsx
import { Button } from '@wandercom/design-system-web/ui/button';

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

### Composition

Compose with other components using `asChild`:

```tsx
import { Button } from '@wandercom/design-system-web/ui/button';
import Link from 'next/link';

export function LinkButton() {
  return (
    <Button asChild>
      <Link href="/dashboard">Dashboard</Link>
    </Button>
  );
}
```

## Variants

### Primary

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

function XIcon() {
  return (
    <svg
      aria-label="Close icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M18 6 6 18" />
      <path d="m6 6 12 12" />
    </svg>
  );
}

function ArrowIcon() {
  return (
    <svg
      aria-label="Arrow icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M5 12h14" />
      <path d="m12 5 7 7-7 7" />
    </svg>
  );
}

export function ButtonVariantPrimary() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button size="xs" variant="primary">
          Extra Small
        </Button>
        <Button size="sm" variant="primary">
          Small
        </Button>
        <Button size="md" variant="primary">
          Medium
        </Button>
        <Button size="lg" variant="primary">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="primary">
          Extra Small
        </Button>
        <Button disabled size="sm" variant="primary">
          Small
        </Button>
        <Button disabled size="md" variant="primary">
          Medium
        </Button>
        <Button disabled size="lg" variant="primary">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="icon-xs" variant="primary">
          <XIcon />
        </Button>
        <Button size="icon-sm" variant="primary">
          <XIcon />
        </Button>
        <Button size="icon-md" variant="primary">
          <XIcon />
        </Button>
        <Button size="icon-lg" variant="primary">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="icon-xs" variant="primary">
          <XIcon />
        </Button>
        <Button disabled size="icon-sm" variant="primary">
          <XIcon />
        </Button>
        <Button disabled size="icon-md" variant="primary">
          <XIcon />
        </Button>
        <Button disabled size="icon-lg" variant="primary">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="xs" variant="primary">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button size="sm" variant="primary">
          <ArrowIcon />
          Small
        </Button>
        <Button size="md" variant="primary">
          <ArrowIcon />
          Medium
        </Button>
        <Button size="lg" variant="primary">
          <ArrowIcon />
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="primary">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button disabled size="sm" variant="primary">
          <ArrowIcon />
          Small
        </Button>
        <Button disabled size="md" variant="primary">
          <ArrowIcon />
          Medium
        </Button>
        <Button disabled size="lg" variant="primary">
          <ArrowIcon />
          Large
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="primary">Primary</Button>
```

### Secondary

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

function XIcon() {
  return (
    <svg
      aria-label="Close icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M18 6 6 18" />
      <path d="m6 6 12 12" />
    </svg>
  );
}

function ArrowIcon() {
  return (
    <svg
      aria-label="Arrow icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M5 12h14" />
      <path d="m12 5 7 7-7 7" />
    </svg>
  );
}

export function ButtonVariantSecondary() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button size="xs" variant="secondary">
          Extra Small
        </Button>
        <Button size="sm" variant="secondary">
          Small
        </Button>
        <Button size="md" variant="secondary">
          Medium
        </Button>
        <Button size="lg" variant="secondary">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="secondary">
          Extra Small
        </Button>
        <Button disabled size="sm" variant="secondary">
          Small
        </Button>
        <Button disabled size="md" variant="secondary">
          Medium
        </Button>
        <Button disabled size="lg" variant="secondary">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="icon-xs" variant="secondary">
          <XIcon />
        </Button>
        <Button size="icon-sm" variant="secondary">
          <XIcon />
        </Button>
        <Button size="icon-md" variant="secondary">
          <XIcon />
        </Button>
        <Button size="icon-lg" variant="secondary">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="icon-xs" variant="secondary">
          <XIcon />
        </Button>
        <Button disabled size="icon-sm" variant="secondary">
          <XIcon />
        </Button>
        <Button disabled size="icon-md" variant="secondary">
          <XIcon />
        </Button>
        <Button disabled size="icon-lg" variant="secondary">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="xs" variant="secondary">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button size="sm" variant="secondary">
          <ArrowIcon />
          Small
        </Button>
        <Button size="md" variant="secondary">
          <ArrowIcon />
          Medium
        </Button>
        <Button size="lg" variant="secondary">
          <ArrowIcon />
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="secondary">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button disabled size="sm" variant="secondary">
          <ArrowIcon />
          Small
        </Button>
        <Button disabled size="md" variant="secondary">
          <ArrowIcon />
          Medium
        </Button>
        <Button disabled size="lg" variant="secondary">
          <ArrowIcon />
          Large
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="secondary">Secondary</Button>
```

### Outline

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

function XIcon() {
  return (
    <svg
      aria-label="Close icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M18 6 6 18" />
      <path d="m6 6 12 12" />
    </svg>
  );
}

function ArrowIcon() {
  return (
    <svg
      aria-label="Arrow icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M5 12h14" />
      <path d="m12 5 7 7-7 7" />
    </svg>
  );
}

export function ButtonVariantOutline() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button size="xs" variant="outline">
          Extra Small
        </Button>
        <Button size="sm" variant="outline">
          Small
        </Button>
        <Button size="md" variant="outline">
          Medium
        </Button>
        <Button size="lg" variant="outline">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="outline">
          Extra Small
        </Button>
        <Button disabled size="sm" variant="outline">
          Small
        </Button>
        <Button disabled size="md" variant="outline">
          Medium
        </Button>
        <Button disabled size="lg" variant="outline">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="icon-xs" variant="outline">
          <XIcon />
        </Button>
        <Button size="icon-sm" variant="outline">
          <XIcon />
        </Button>
        <Button size="icon-md" variant="outline">
          <XIcon />
        </Button>
        <Button size="icon-lg" variant="outline">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="icon-xs" variant="outline">
          <XIcon />
        </Button>
        <Button disabled size="icon-sm" variant="outline">
          <XIcon />
        </Button>
        <Button disabled size="icon-md" variant="outline">
          <XIcon />
        </Button>
        <Button disabled size="icon-lg" variant="outline">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="xs" variant="outline">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button size="sm" variant="outline">
          <ArrowIcon />
          Small
        </Button>
        <Button size="md" variant="outline">
          <ArrowIcon />
          Medium
        </Button>
        <Button size="lg" variant="outline">
          <ArrowIcon />
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="outline">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button disabled size="sm" variant="outline">
          <ArrowIcon />
          Small
        </Button>
        <Button disabled size="md" variant="outline">
          <ArrowIcon />
          Medium
        </Button>
        <Button disabled size="lg" variant="outline">
          <ArrowIcon />
          Large
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="outline">Outline</Button>
```

### Ghost

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

function XIcon() {
  return (
    <svg
      aria-label="Close icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M18 6 6 18" />
      <path d="m6 6 12 12" />
    </svg>
  );
}

function ArrowIcon() {
  return (
    <svg
      aria-label="Arrow icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M5 12h14" />
      <path d="m12 5 7 7-7 7" />
    </svg>
  );
}

export function ButtonVariantGhost() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button size="xs" variant="ghost">
          Extra Small
        </Button>
        <Button size="sm" variant="ghost">
          Small
        </Button>
        <Button size="md" variant="ghost">
          Medium
        </Button>
        <Button size="lg" variant="ghost">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="ghost">
          Extra Small
        </Button>
        <Button disabled size="sm" variant="ghost">
          Small
        </Button>
        <Button disabled size="md" variant="ghost">
          Medium
        </Button>
        <Button disabled size="lg" variant="ghost">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="icon-xs" variant="ghost">
          <XIcon />
        </Button>
        <Button size="icon-sm" variant="ghost">
          <XIcon />
        </Button>
        <Button size="icon-md" variant="ghost">
          <XIcon />
        </Button>
        <Button size="icon-lg" variant="ghost">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="icon-xs" variant="ghost">
          <XIcon />
        </Button>
        <Button disabled size="icon-sm" variant="ghost">
          <XIcon />
        </Button>
        <Button disabled size="icon-md" variant="ghost">
          <XIcon />
        </Button>
        <Button disabled size="icon-lg" variant="ghost">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="xs" variant="ghost">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button size="sm" variant="ghost">
          <ArrowIcon />
          Small
        </Button>
        <Button size="md" variant="ghost">
          <ArrowIcon />
          Medium
        </Button>
        <Button size="lg" variant="ghost">
          <ArrowIcon />
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="ghost">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button disabled size="sm" variant="ghost">
          <ArrowIcon />
          Small
        </Button>
        <Button disabled size="md" variant="ghost">
          <ArrowIcon />
          Medium
        </Button>
        <Button disabled size="lg" variant="ghost">
          <ArrowIcon />
          Large
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="ghost">Ghost</Button>
```

### Destructive

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

function XIcon() {
  return (
    <svg
      aria-label="Close icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M18 6 6 18" />
      <path d="m6 6 12 12" />
    </svg>
  );
}

function ArrowIcon() {
  return (
    <svg
      aria-label="Arrow icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M5 12h14" />
      <path d="m12 5 7 7-7 7" />
    </svg>
  );
}

export function ButtonVariantDestructive() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button size="xs" variant="destructive">
          Extra Small
        </Button>
        <Button size="sm" variant="destructive">
          Small
        </Button>
        <Button size="md" variant="destructive">
          Medium
        </Button>
        <Button size="lg" variant="destructive">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="destructive">
          Extra Small
        </Button>
        <Button disabled size="sm" variant="destructive">
          Small
        </Button>
        <Button disabled size="md" variant="destructive">
          Medium
        </Button>
        <Button disabled size="lg" variant="destructive">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="icon-xs" variant="destructive">
          <XIcon />
        </Button>
        <Button size="icon-sm" variant="destructive">
          <XIcon />
        </Button>
        <Button size="icon-md" variant="destructive">
          <XIcon />
        </Button>
        <Button size="icon-lg" variant="destructive">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="icon-xs" variant="destructive">
          <XIcon />
        </Button>
        <Button disabled size="icon-sm" variant="destructive">
          <XIcon />
        </Button>
        <Button disabled size="icon-md" variant="destructive">
          <XIcon />
        </Button>
        <Button disabled size="icon-lg" variant="destructive">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="xs" variant="destructive">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button size="sm" variant="destructive">
          <ArrowIcon />
          Small
        </Button>
        <Button size="md" variant="destructive">
          <ArrowIcon />
          Medium
        </Button>
        <Button size="lg" variant="destructive">
          <ArrowIcon />
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="destructive">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button disabled size="sm" variant="destructive">
          <ArrowIcon />
          Small
        </Button>
        <Button disabled size="md" variant="destructive">
          <ArrowIcon />
          Medium
        </Button>
        <Button disabled size="lg" variant="destructive">
          <ArrowIcon />
          Large
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="destructive">Destructive</Button>
```

### Checkout

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

function XIcon() {
  return (
    <svg
      aria-label="Close icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M18 6 6 18" />
      <path d="m6 6 12 12" />
    </svg>
  );
}

function ArrowIcon() {
  return (
    <svg
      aria-label="Arrow icon"
      fill="none"
      height="16"
      role="img"
      stroke="currentColor"
      strokeLinecap="round"
      strokeLinejoin="round"
      strokeWidth="2"
      viewBox="0 0 24 24"
      width="16"
      xmlns="http://www.w3.org/2000/svg"
    >
      <path d="M5 12h14" />
      <path d="m12 5 7 7-7 7" />
    </svg>
  );
}

export function ButtonVariantCheckout() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button size="xs" variant="checkout">
          Extra Small
        </Button>
        <Button size="sm" variant="checkout">
          Small
        </Button>
        <Button size="md" variant="checkout">
          Medium
        </Button>
        <Button size="lg" variant="checkout">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="checkout">
          Extra Small
        </Button>
        <Button disabled size="sm" variant="checkout">
          Small
        </Button>
        <Button disabled size="md" variant="checkout">
          Medium
        </Button>
        <Button disabled size="lg" variant="checkout">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="icon-xs" variant="checkout">
          <XIcon />
        </Button>
        <Button size="icon-sm" variant="checkout">
          <XIcon />
        </Button>
        <Button size="icon-md" variant="checkout">
          <XIcon />
        </Button>
        <Button size="icon-lg" variant="checkout">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="icon-xs" variant="checkout">
          <XIcon />
        </Button>
        <Button disabled size="icon-sm" variant="checkout">
          <XIcon />
        </Button>
        <Button disabled size="icon-md" variant="checkout">
          <XIcon />
        </Button>
        <Button disabled size="icon-lg" variant="checkout">
          <XIcon />
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button size="xs" variant="checkout">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button size="sm" variant="checkout">
          <ArrowIcon />
          Small
        </Button>
        <Button size="md" variant="checkout">
          <ArrowIcon />
          Medium
        </Button>
        <Button size="lg" variant="checkout">
          <ArrowIcon />
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button disabled size="xs" variant="checkout">
          <ArrowIcon />
          Extra Small
        </Button>
        <Button disabled size="sm" variant="checkout">
          <ArrowIcon />
          Small
        </Button>
        <Button disabled size="md" variant="checkout">
          <ArrowIcon />
          Medium
        </Button>
        <Button disabled size="lg" variant="checkout">
          <ArrowIcon />
          Large
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="checkout">Checkout</Button>
```

### Link

```tsx
import { Button } from "@wandercom/design-system-web/ui/button";

export function ButtonVariantLink() {
  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button variant="link">Link Button</Button>
        <Button disabled variant="link">
          Disabled Link
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button variant="link">Link</Button>
```

## Loading

Set `loading` to show an animated spinner and disable the button. For standard buttons the spinner appears inline before the label. For icon-only and `asChild` buttons, the spinner overlays the content.

```tsx
"use client";

import { Button } from "@wandercom/design-system-web/ui/button";
import { useState } from "react";

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

  return (
    <div className="flex flex-col gap-6">
      <div className="flex items-center gap-4">
        <Button loading size="xs" variant="primary">
          Extra Small
        </Button>
        <Button loading size="sm" variant="primary">
          Small
        </Button>
        <Button loading size="md" variant="primary">
          Medium
        </Button>
        <Button loading size="lg" variant="primary">
          Large
        </Button>
      </div>
      <div className="flex items-center gap-4">
        <Button loading={loading} size="xs" variant="primary">
          Extra Small
        </Button>
        <Button loading={loading} size="sm" variant="primary">
          Small
        </Button>
        <Button loading={loading} size="md" variant="primary">
          Medium
        </Button>
        <Button loading={loading} size="lg" variant="primary">
          Large
        </Button>
      </div>
      <div>
        <Button
          onClick={() => setLoading((prev) => !prev)}
          size="sm"
          variant="outline"
        >
          {loading ? "Stop Loading" : "Start Loading"}
        </Button>
      </div>
    </div>
  );
}

```

```tsx
<Button loading>Continue</Button>
```

## Sizes

Four text sizes and four icon-only sizes are available. The default size is `lg`.

```tsx
<Button size="xs">Extra small</Button>
<Button size="sm">Small</Button>
<Button size="md">Medium</Button>
<Button size="lg">Large</Button>

<Button size="icon-xs">
  <Icon />
</Button>
<Button size="icon-sm">
  <Icon />
</Button>
<Button size="icon-md">
  <Icon />
</Button>
<Button size="icon-lg">
  <Icon />
</Button>
```

## Props

| Prop | Type | Description |
| --- | --- | --- |
| variant? | `'primary' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'checkout' | 'link' | 'unstyled'` | Visual style variant. Defaults to 'primary'. |
| size? | `'xs' | 'sm' | 'md' | 'lg' | 'icon-xs' | 'icon-sm' | 'icon-md' | 'icon-lg'` | Size variant. Defaults to 'lg'. |
| loading? | `boolean` | When true, shows an animated spinner and disables the button. Defaults to false. |
| asChild? | `boolean` | Renders the child element and merges props instead of rendering a native button. Uses Radix UI Slot. Defaults to false. |
| disabled? | `boolean` | Disables the button when true. Also set automatically when loading is true. |
| className? | `string` | Additional CSS classes. |

## Accessibility

The Button renders a native `<button>` element by default, inheriting built-in keyboard and screen reader support. When using `asChild`, ensure the child element is focusable and has the correct role.

**Keyboard interaction:**
- `Space` - Activates the button
- `Enter` - Activates the button

When `loading` is true the button is automatically disabled, preventing duplicate submissions. The spinner is marked with `aria-hidden` when not active.

For icon-only buttons, always provide an accessible label via `aria-label` or visually hidden text so screen readers can announce the button's purpose.