# Button

> Button triggers an action or event when clicked. It can contain text, an icon, or both, and is a primary way for users to interact with the app.

Source: https://vaneui.com/docs/basic-components/button

Import: `import { Button, Col, Row, ThemeProvider } from "@vaneui/ui"`

Use Button for actions, [Link](/docs/typography-components/link) for an in-prose hyperlink, and [NavLink](/docs/basic-components/navlink) for a sidebar or navigation item. An action shown only as an icon goes in an [IconButton](/docs/basic-components/icon-button). Button renders a native `<button>`, or an `<a>` when `href` is set. A `disabled` or `loading` Button with an `href` drops the `href` but stays focusable, marked with `aria-disabled`.

## Basic usage

Button triggers an action when the user clicks it; each `appearance` prop maps to a semantic color from the active theme.

```tsx demo
<Row flexWrap>
  <Button primary>primary</Button>
  <Button accent>accent</Button>
  <Button secondary>secondary</Button>
  <Button tertiary>tertiary</Button>
  <Button success>success</Button>
  <Button danger>danger</Button>
  <Button warning>warning</Button>
  <Button info>info</Button>
  <Button inheritAppearance>inheritAppearance</Button>
</Row>
```

## Sizes

Buttons come in five sizes: `xs`, `sm` (default), `md`, `lg`, `xl`. Size drives font-size, padding, gap, and border-radius simultaneously via CSS variables.

```tsx demo
<Row flexWrap>
  <Button xs>xs</Button>
  <Button sm>sm</Button>
  <Button md>md</Button>
  <Button lg>lg</Button>
  <Button xl>xl</Button>
</Row>
```

## Variants

Buttons can be styled as `filled`, `outline` (default), or `ghost`.

```tsx demo
<Col>
  <Row flexWrap>
    <Button filled primary>primary</Button>
    <Button filled accent>accent</Button>
    <Button filled secondary>secondary</Button>
  </Row>
  <Row flexWrap>
    <Button primary>primary</Button>
    <Button accent>accent</Button>
    <Button secondary>secondary</Button>
  </Row>
  <Row flexWrap>
    <Button ghost primary>primary</Button>
    <Button ghost accent>accent</Button>
    <Button ghost secondary>secondary</Button>
  </Row>
</Col>
```

## Shapes

Button supports three border-radius styles: `rounded` (default), `pill`, and `sharp`.

```tsx demo
<Row flexWrap>
  <Button pill>Subscribe</Button>
  <Button sharp>Subscribe</Button>
  <Button rounded>Subscribe</Button>
</Row>
```

## With icon

Drop an icon directly inside the button. `gap` is on by default, so spacing is automatic.

```tsx demo
<Row flexWrap>
  <Button><Download/> Download</Button>
  <Button success filled><Check/> Saved</Button>
  <Button danger><Trash2/> Delete</Button>
  <Button secondary>Next <ArrowRight/></Button>
</Row>
```

## Sizes with icon

The same size matrix paired with an inline icon.

```tsx demo
<Row flexWrap>
  <Button xs><Star/> Extra Small</Button>
  <Button sm><Star/> Small</Button>
  <Button md><Star/> Medium</Button>
  <Button lg><Star/> Large</Button>
  <Button xl><Star/> Extra Large</Button>
</Row>
```

## Font weights

Buttons default to `fontSemibold`. Use any of the standard weight props to override.

```tsx demo
<Row flexWrap>
  <Button fontThin>Submit</Button>
  <Button fontExtralight>Submit</Button>
  <Button fontLight>Submit</Button>
  <Button fontNormal>Submit</Button>
  <Button fontMedium>Submit</Button>
  <Button fontSemibold>Submit</Button>
  <Button fontBold>Submit</Button>
  <Button fontExtrabold>Submit</Button>
  <Button fontBlack>Submit</Button>
</Row>
```

## As Link and disabled

Pass `href` to render the button as an `<a>` for navigation. Use `disabled` to prevent interaction.

```tsx demo
<Row flexWrap>
  <Button href="#">Link Button</Button>
  <Button success filled href="#">Success Link</Button>
  <Button disabled>Disabled</Button>
  <Button danger filled disabled>Disabled Danger</Button>
</Row>
```

## Loading state

Set `loading` to swap the label for a spinner and auto-disable the button. The width is kept, so the layout does not jump when the state flips.

```tsx demo
<Row flexWrap itemsCenter>
  <Button loading>Saving</Button>
  <Button loading filled danger>Deleting</Button>
  <Button loading lg>Large</Button>
</Row>
```

The ring is the `Spinner` component, so there is one spinner in the library and restyling `theme.spinner` restyles both. The button forwards its own size, and the ring inherits the button's text colour: a filled button gets a light ring, an outline button a dark one.

It is decorative here rather than a live region. The button already carries `aria-busy`, so the Spinner's `role="status"` is suppressed and the accessible name stays the button's own.

```tsx demo
const [loading, setLoading] = useState(false);

return (
  <Button loading={loading} onClick={() => setLoading(true)}>
    Submit
  </Button>
);
```

## Next.js Link integration

Use the `tag` prop to render the button as a Next.js `Link` for client-side navigation.

```tsx
import Link from 'next/link';
import { Button } from '@vaneui/ui';

<Button href="/docs" tag={Link}>Documentation</Button>
```

## Customizing

Set app-wide Button defaults with `ThemeProvider`'s `themeDefaults`:

```tsx demo
<ThemeProvider themeDefaults={{
  button: { main: { primary: true, lg: true, filled: true } },
}}>
  <Button>Submit</Button>
</ThemeProvider>
```

Add prop-conditional classes with `extraClasses`, applied whenever the matching boolean prop is active. For compound themes like Button, nest the prop-class map under the sub-theme name (`main` for Button's primary surface):

```tsx demo
<ThemeProvider extraClasses={{
  button: {
    main: {
      primary: 'shadow-lg hover:shadow-xl transition-shadow',
      danger: 'animate-pulse',
    },
  },
}}>
  <Button primary>Glowing Primary</Button>
</ThemeProvider>
```

## Props

| Prop | Category | Default | Description |
| --- | --- | --- | --- |
| `primary` | Appearance | yes | Primary color appearance (gray) |
| `accent` | Appearance |  | Accent color appearance (rose) |
| `secondary` | Appearance |  | Secondary color appearance (gray) |
| `tertiary` | Appearance |  | Tertiary color appearance |
| `success` | Appearance |  | Success color appearance (green) |
| `danger` | Appearance |  | Danger color appearance (red) |
| `warning` | Appearance |  | Warning color appearance (amber) |
| `info` | Appearance |  | Info color appearance (cyan) |
| `inheritAppearance` | Appearance |  | Inherit appearance from parent — suppresses own data-appearance/data-variant, uses parent's CSS variables |
| `disabled` | Disabled |  | Disable the component — reduces opacity, changes cursor to not-allowed, and prevents interaction |
| `flex1` | Flex |  | Take up remaining space (= `flex-1`, i.e. `flex: 1 1 0%`) |
| `flexAuto` | Flex |  | Grow but respect intrinsic size (= `flex-auto`, i.e. `flex: 1 1 auto`) |
| `flexNone` | Flex |  | Don't grow and don't shrink (= `flex-none`, i.e. `flex: none`) |
| `fontSans` | Font Family | yes | Sans-serif font family (default) — emits font-sans |
| `fontSerif` | Font Family |  | Serif font family — emits font-serif |
| `fontMono` | Font Family |  | Monospace font family — emits font-mono |
| `fontHeading` | Font Family |  | Heading font family (defaults to sans, customizable via --font-heading) — emits font-heading |
| `italic` | Font Style |  | Italic font style |
| `notItalic` | Font Style |  | Not italic (normal) font style |
| `fontThin` | Font Weight |  | Thin font weight (100) — emits font-thin |
| `fontExtralight` | Font Weight |  | Extra light font weight (200) — emits font-extralight |
| `fontLight` | Font Weight |  | Light font weight (300) — emits font-light |
| `fontNormal` | Font Weight |  | Normal font weight (400) — emits font-normal |
| `fontMedium` | Font Weight |  | Medium font weight (500) — emits font-medium |
| `fontSemibold` | Font Weight | yes | Semibold font weight (600) — emits font-semibold |
| `fontBold` | Font Weight |  | Bold font weight (700) — emits font-bold |
| `fontExtrabold` | Font Weight |  | Extra bold font weight (800) — emits font-extrabold |
| `fontBlack` | Font Weight |  | Black font weight (900) — emits font-black |
| `inheritSize` | Inherit Size |  | Inherit font-size and line-height from the nearest parent typography element |
| `noInheritSize` | Inherit Size |  | Keep own font-size; do not inherit from parent |
| `padding` | Padding | yes | Enable internal padding |
| `paddingX` | Padding |  | Enable only horizontal padding |
| `paddingY` | Padding |  | Enable only vertical padding |
| `noPadding` | Padding |  | Disable internal padding |
| `pill` | Shape |  | Fully rounded corners (circular) |
| `sharp` | Shape |  | No rounded corners (square) |
| `rounded` | Shape | yes | Medium rounded corners (default) |
| `noShrink` | Shrink |  | Prevent the flex item from shrinking below its content size (= `shrink-0`) |
| `xs` | Size |  | Extra small size |
| `sm` | Size | yes | Small size |
| `md` | Size |  | Medium size (default) |
| `lg` | Size |  | Large size |
| `xl` | Size |  | Extra large size |
| `textLeft` | Text Align |  | Align text to left (physical side, does not flip under RTL) |
| `textCenter` | Text Align | yes | Align text to center |
| `textRight` | Text Align |  | Align text to right (physical side, does not flip under RTL) |
| `textJustify` | Text Align |  | Justify text |
| `textStart` | Text Align |  | Align text to the reading-direction start (left in LTR, right in RTL) |
| `textEnd` | Text Align |  | Align text to the reading-direction end (right in LTR, left in RTL) |
| `underline` | Text Decoration |  | Add underline decoration below text |
| `lineThrough` | Text Decoration |  | Add strikethrough/line-through decoration across text |
| `noUnderline` | Text Decoration |  | Remove ALL text-decoration — underline, line-through, and overline (text-decoration: none) |
| `overline` | Text Decoration |  | Add overline decoration above text |
| `uppercase` | Text Transform |  | Transform text to uppercase |
| `lowercase` | Text Transform |  | Transform text to lowercase |
| `capitalize` | Text Transform |  | Capitalize first letter of each word |
| `normalCase` | Text Transform |  | Normal text case (no transformation) |
| `filled` | Variant |  | Filled variant - solid background with contrasting text color |
| `outline` | Variant | yes | Outline variant - transparent background with border and colored text (default) |
| `ghost` | Variant |  | Ghost variant - transparent background, no border, appearance-colored text, tinted hover background |
| `breakNormal` | Word Break |  | Reset breaking - overflow-wrap and word-break normal |
| `breakWords` | Word Break |  | Break long words to prevent overflow - overflow-wrap: break-word |
| `breakAll` | Word Break |  | Break between any two characters - word-break: break-all |
| `breakKeep` | Word Break |  | Do not break CJK text - word-break: keep-all |

Layout and utility props (Border, Cursor, Display, Flex Direction, Focus Visible, Gap, Height, Hide, Items, Justify, Overflow, Position, Responsive Sizing, Responsive Width, Ring, Shadow, Show, Transition, Transparent, Whitespace, Width, Wrap) are listed on [Common Props](https://vaneui.com/docs/reference/common-props.md).
