> For AI agents: the complete documentation index is available at https://wallarm.github.io/design-system/llms.txt, the full documentation bundle is available at https://wallarm.github.io/design-system/llms-full.txt.

# Button

Triggers an action — reach for `Link` when the control navigates somewhere instead, `ToggleButton` when it stays switched on, and `SplitButton` or `DropdownMenu` when several related actions compete for one slot. Keep one `variant='primary'` per view, and reserve `color='destructive'` for actions that are hard to undo.

[Source](https://github.com/wallarm/design-system/tree/main/packages/design-system/src/components/Button) · [Storybook](https://wallarm.github.io/design-system/storybook/?path=/docs/actions-button--overview)

```tsx
import { Button } from '@wallarm-org/design-system/Button';

export const Basic = () => {
  return (
    <Button data-testid='button'>
      Button
    </Button>
  );
};
```

## Usage

```tsx
import { Button } from '@wallarm-org/design-system/Button';
```

## Examples

### Variants

`variant` sets emphasis and `color` sets meaning, and only the pairings drawn here are
designed: `primary` exists for `brand` and `destructive` only. `neutral-alt` has ghost and
secondary variants, shown on an inverted surface so they remain readable in both themes.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { HStack, VStack } from '@wallarm-org/design-system/Stack';

export const Variants = () => (
  <VStack>
    <HStack>
      <Button variant='primary' color='brand'>
        Primary
      </Button>
      <Button variant='ghost' color='brand'>
        Ghost
      </Button>
      <Button variant='secondary' color='brand'>
        Secondary
      </Button>
    </HStack>
    <HStack>
      <Button variant='outline' color='neutral'>
        Outline
      </Button>
      <Button variant='ghost' color='neutral'>
        Ghost
      </Button>
      <Button variant='secondary' color='neutral'>
        Secondary
      </Button>
    </HStack>
    <HStack className='rounded-8 bg-component-toast-bg p-8'>
      <Button variant='ghost' color='neutral-alt'>
        Ghost
      </Button>
      <Button variant='secondary' color='neutral-alt'>
        Secondary
      </Button>
    </HStack>
    <HStack>
      <Button variant='primary' color='destructive'>
        Primary
      </Button>
      <Button variant='outline' color='destructive'>
        Outline
      </Button>
      <Button variant='ghost' color='destructive'>
        Ghost
      </Button>
      <Button variant='secondary' color='destructive'>
        Secondary
      </Button>
    </HStack>
  </VStack>
);
```

### Sizes

Three heights at identical emphasis; `large` is the default, and the smaller two are for
dense contexts like table rows and toolbars where a full-height button would dominate.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { HStack } from '@wallarm-org/design-system/Stack';

export const Sizes = () => (
  <HStack align='end' justify='center'>
    <Button size='small'>
      Small
    </Button>
    <Button size='medium'>
      Medium
    </Button>
    <Button size='large'>
      Large
    </Button>
  </HStack>
);
```

### Disabled

Every sanctioned pairing with the action unavailable. `disabled` also takes the button out
of the tab order, so say somewhere on screen what would re-enable it rather than leaving the
reader to guess.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { HStack, VStack } from '@wallarm-org/design-system/Stack';

export const Disabled = () => (
  <VStack>
    <HStack>
      <Button variant='primary' color='brand' disabled>
        Primary
      </Button>
      <Button variant='ghost' color='brand' disabled>
        Ghost
      </Button>
      <Button variant='secondary' color='brand' disabled>
        Secondary
      </Button>
    </HStack>
    <HStack>
      <Button variant='outline' color='neutral' disabled>
        Outline
      </Button>
      <Button variant='ghost' color='neutral' disabled>
        Ghost
      </Button>
      <Button variant='secondary' color='neutral' disabled>
        Secondary
      </Button>
    </HStack>
    <HStack className='rounded-8 bg-component-toast-bg p-8'>
      <Button variant='ghost' color='neutral-alt' disabled>
        Ghost
      </Button>
      <Button variant='secondary' color='neutral-alt' disabled>
        Secondary
      </Button>
    </HStack>
    <HStack>
      <Button variant='primary' color='destructive' disabled>
        Primary
      </Button>
      <Button variant='outline' color='destructive' disabled>
        Outline
      </Button>
      <Button variant='ghost' color='destructive' disabled>
        Ghost
      </Button>
      <Button variant='secondary' color='destructive' disabled>
        Secondary
      </Button>
    </HStack>
  </VStack>
);
```

### Loading

`loading` covers the content with a spinner but keeps the label's footprint, so the button
doesn't resize mid-request. It disables the button on its own — passing `disabled` as well is
redundant.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { HStack, VStack } from '@wallarm-org/design-system/Stack';

export const Loading = () => (
  <VStack>
    <HStack>
      <Button variant='primary' color='brand' loading>
        Primary
      </Button>
      <Button variant='ghost' color='brand' loading>
        Ghost
      </Button>
      <Button variant='secondary' color='brand' loading>
        Secondary
      </Button>
    </HStack>
    <HStack>
      <Button variant='outline' color='neutral' loading>
        Outline
      </Button>
      <Button variant='ghost' color='neutral' loading>
        Ghost
      </Button>
      <Button variant='secondary' color='neutral' loading>
        Secondary
      </Button>
    </HStack>
    <HStack className='rounded-8 bg-component-toast-bg p-8'>
      <Button variant='ghost' color='neutral-alt' loading>
        Ghost
      </Button>
      <Button variant='secondary' color='neutral-alt' loading>
        Secondary
      </Button>
    </HStack>
    <HStack>
      <Button variant='primary' color='destructive' loading>
        Primary
      </Button>
      <Button variant='outline' color='destructive' loading>
        Outline
      </Button>
      <Button variant='ghost' color='destructive' loading>
        Ghost
      </Button>
      <Button variant='secondary' color='destructive' loading>
        Secondary
      </Button>
    </HStack>
  </VStack>
);
```

### Icons

An icon before the label, after it, or both. The button sizes and spaces icons itself, so
pass the icon bare; and if one button in a row carries an icon, they all should.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { ChevronLeft, ChevronRight } from '@wallarm-org/design-system/icons';
import { HStack } from '@wallarm-org/design-system/Stack';

export const Icons = () => (
  <HStack>
    <Button>
      <ChevronLeft />
      Left icon
    </Button>

    <Button>
      Right icon
      <ChevronRight />
    </Button>

    <Button>
      <ChevronLeft />2 icons
      <ChevronRight />
    </Button>
  </HStack>
);
```

### Badge

A `NumericBadge` after the label, for a count the action applies to. The button tightens
its right padding whenever the last child isn't text, so a trailing badge or icon doesn't sit
stranded.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { NumericBadge } from '@wallarm-org/design-system/NumericBadge';

export const Badge = () => (
  <Button>
    With badge
    <NumericBadge type='outline'>1</NumericBadge>
  </Button>
);
```

### Icon only

There is no `iconOnly` prop: a button whose only child is an icon squares itself off. Give
it an `aria-label` naming the action and a `Tooltip`, since nothing on screen says what it does.

```tsx
import { Button } from '@wallarm-org/design-system/Button';
import { ChevronRight } from '@wallarm-org/design-system/icons';
import { HStack } from '@wallarm-org/design-system/Stack';

export const IconOnly = () => (
  <HStack>
    <Button>
      <ChevronRight />
    </Button>

    <Button loading>
      <ChevronRight />
    </Button>

    <Button disabled>
      <ChevronRight />
    </Button>
  </HStack>
);
```

### Link as button

`asChild` puts the button's styling on your own `<a>`, so the element stays a real link and
middle-click and “open in new tab” keep working. Use it only when a navigation has to carry a
button's weight; ordinary navigation is a `Link`.

```tsx
import { Button } from '@wallarm-org/design-system/Button';

export const LinkAsButton = () => (
  <Button asChild>
    <a href='https://google.com' target='_blank' rel='noopener noreferrer'>
      Button as link
    </a>
  </Button>
);
```

### Full width

`fullWidth` fills the container, for narrow surfaces like a `Drawer` or a dialog footer
rather than a wide desktop form. Two full-width buttons side by side split the row evenly
instead of overflowing it.

```tsx
import { Button } from '@wallarm-org/design-system/Button';

export const FullWidth = () => (
  <div className='w-400'>
    <Button fullWidth>
      Full width example
    </Button>
  </div>
);
```

## Props

| Prop        | Type                                                                              | Default   | Description |
| ----------- | --------------------------------------------------------------------------------- | --------- | ----------- |
| size        | `{ small: string; medium: string; large: string; 'inline-edit': string; }`        | `large`   |             |
| loading     | `{ true: string; }`                                                               | `false`   |             |
| fullWidth   | `{ true: string; false: string; }`                                                |           |             |
| asChild     | `boolean \| undefined`                                                            | `false`   |             |
| data-testid | `string \| undefined`                                                             |           |             |
| as          | `C \| undefined`                                                                  |           |             |
| color       | `{ brand: string; neutral: string; 'neutral-alt': string; destructive: string; }` | `brand`   |             |
| variant     | `{ primary: string; outline: string; ghost: string; secondary: string; }`         | `primary` |             |
