---
title: Button
description: "Displays a button or a component that looks like a button. Built on Base UI, styled with StyleX."
---

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonDemo() {
  return (
    <Button variant="outline">
      <svg width="16" height="16" viewBox={`0 0 16 16`} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden>
        <path d={`M8 3v10M3 8h10`} />
      </svg>
      New project
    </Button>
  );
}
```

## Install

```bash
npx shadcn@latest add @madeui/button
```

## Usage

```tsx
import { Button } from '@/components/ui/button';

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

## Default

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonDefault() {
  return <Button>Button</Button>;
}
```

## Secondary

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonSecondary() {
  return <Button variant="secondary">Secondary</Button>;
}
```

## Outline

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonOutline() {
  return <Button variant="outline">Outline</Button>;
}
```

## Ghost

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonGhost() {
  return <Button variant="ghost">Ghost</Button>;
}
```

## Destructive

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonDestructive() {
  return <Button variant="destructive">Destructive</Button>;
}
```

## Sizes

```tsx
import * as stylex from '@stylexjs/stylex';

import { space } from '@/lib/constants.stylex';

import { Button } from '@/components/ui/button';

export default function ButtonSizes() {
  return (
    <div {...stylex.props(styles.row)}>
      <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>
  );
}

const styles = stylex.create({
  row: {
    alignItems: 'center',
    display: 'flex',
    flexWrap: 'wrap',
    gap: space.s2,
  },
});
```

## Icon

Use `size="icon"` for a square, icon-only button. Always set `aria-label`.

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonIcon() {
  return (
    <Button size="icon" variant="outline" aria-label="Add">
      <svg width="16" height="16" viewBox={`0 0 16 16`} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden>
        <path d={`M8 3v10M3 8h10`} />
      </svg>
    </Button>
  );
}
```

## Icon sizes

`icon` pairs with `md`; use `iconXs`, `iconSm`, and `iconLg` to match the `xs`, `sm`, and `lg` text sizes.

```tsx
import * as stylex from '@stylexjs/stylex';

import { space } from '@/lib/constants.stylex';

import { Button } from '@/components/ui/button';

export default function ButtonIconSizes() {
  return (
    <div {...stylex.props(styles.row)}>
      <Button size="iconXs" variant="outline" aria-label="Add">
        <svg width="16" height="16" viewBox={`0 0 16 16`} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden>
          <path d={`M8 3v10M3 8h10`} />
        </svg>
      </Button>
      <Button size="iconSm" variant="outline" aria-label="Add">
        <svg width="16" height="16" viewBox={`0 0 16 16`} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden>
          <path d={`M8 3v10M3 8h10`} />
        </svg>
      </Button>
      <Button size="icon" variant="outline" aria-label="Add">
        <svg width="16" height="16" viewBox={`0 0 16 16`} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden>
          <path d={`M8 3v10M3 8h10`} />
        </svg>
      </Button>
      <Button size="iconLg" variant="outline" aria-label="Add">
        <svg width="16" height="16" viewBox={`0 0 16 16`} fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden>
          <path d={`M8 3v10M3 8h10`} />
        </svg>
      </Button>
    </div>
  );
}

const styles = stylex.create({
  row: {
    alignItems: 'center',
    display: 'flex',
    flexWrap: 'wrap',
    gap: space.s2,
  },
});
```

## Loading

Render a `<Spinner />` before the label and set `disabled` to show a loading state.

```tsx
import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';

export default function ButtonLoading() {
  return (
    <Button disabled>
      <Spinner />
      Please wait
    </Button>
  );
}
```

## Disabled

```tsx
import { Button } from '@/components/ui/button';

export default function ButtonDisabled() {
  return <Button disabled>Disabled</Button>;
}
```

## Rounded

Per-instance overrides go through the `style` prop — StyleX merges it last, so it always wins. No `tailwind-merge`, no `!important`.

```tsx
import * as stylex from '@stylexjs/stylex';

import { radius } from '@/lib/tokens.stylex';

import { Button } from '@/components/ui/button';

// The style prop merges last — StyleX guarantees it wins over the
// component's own styles. No tailwind-merge, no !important.
export default function ButtonRounded() {
  return <Button style={styles.rounded}>Rounded</Button>;
}

const styles = stylex.create({
  rounded: {
    borderRadius: radius.full,
  },
});
```

## As link

The `render` prop swaps the underlying element while keeping the button styling — set `nativeButton={false}` when the element is not a `<button>`.

```tsx
import { Button } from '@/components/ui/button';

// The render prop swaps the underlying element — here an <a> styled as a button.
export default function ButtonAsLink() {
  return (
    <Button variant="outline" render={<a href="#docs" />} nativeButton={false}>
      Read the docs
    </Button>
  );
}
```

## API reference

Built on [Base UI Button](https://base-ui.com/react/components/button). The tables below cover the props this library adds or changes — every other prop is forwarded to the underlying Base UI part; see the [Base UI Button API reference](https://base-ui.com/react/components/button#api-reference) for the full list.

### Button

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'destructive'` | `'primary'` | Visual style. |
| `size` | `'xs' \| 'sm' \| 'md' \| 'lg' \| 'icon' \| 'iconXs' \| 'iconSm' \| 'iconLg'` | `'md'` | `icon`, `iconXs`, `iconSm`, `iconLg` render a square button. |
| `disabled` | `boolean` | `false` |  |
| `style` | `StyleXStyles` | — | StyleX styles merged last — always win over the component's own styles. |
