# Button
> A Button is a clickable element used to trigger an action.

## Import

```js
import { Button } from '@volue/wave-react';
```

## Examples

### Basic

```jsx
<Button>{'Default'}</Button>
```

### Variants

We provide buttons of three "visual" variants: `strong` (high emphasis), `outline` (medium emphasis) and `ghost` (low emphasis).

```jsx
<Flex gap="spacingL">
  <Button variant="strong">{'Strong'}</Button>
  <Button variant="outline">{'Outline'}</Button>
  <Button variant="ghost">{'Ghost'}</Button>
</Flex>
```

### Sizes

Wave provides two button sizes ‐ `medium` and `small`, with exception of lone icon buttons which can also be `xSmall` or `xxSmall`.

- `medium` size buttons are used by default.
- `small` size buttons and `xSmall` lone icon buttons can be used in cases when there is limited space available for rendering, like in data tables or complex dashboards.

```jsx
<Flex gap="spacingL" flow="column">
  <Flex gap="spacingL">
    <Button size="medium">{'Medium'}</Button>
    <Button size="small">{'Small'}</Button>
  </Flex>
  <Flex gap="spacingL">
    <Tooltip content="Medium">
      <Button withLoneIcon size="medium" shape="circle" variant="ghost">
        <SvgIcon iconName="reload" />
      </Button>
    </Tooltip>
    <Tooltip content="Small">
      <Button withLoneIcon size="small" variant="ghost">
        <SvgIcon iconName="reload" />
      </Button>
    </Tooltip>
    <Tooltip content="xSmall">
      <Button withLoneIcon size="xSmall" variant="ghost">
        <SvgIcon iconName="reload" />
      </Button>
    </Tooltip>
    <Tooltip content="xxSmall">
      <Button withLoneIcon size="xxSmall" variant="ghost">
        <SvgIcon iconName="reload" />
      </Button>
    </Tooltip>
  </Flex>
</Flex>
```

#### Responsive

Button supports responsive syntax for its `size` property, which means you can change its size based on the viewport.

```jsx
<Button
  size={{ '@initial': 'medium', '@mqLargeAndUp': 'small' }}
  variant="outline"
>
  {'Responsive button'}
</Button>
```

#### Multi-sizing

Wave provides `applySizes` utility, which lets you specify size "scopes" within your app.

```js
import { applySizes } from '@volue/wave-react';
```

All buttons within a scope will share the same size unless overwritten on a per-control basis.

```jsx
<Flex
  gap="spacingS"
  className={applySizes({
    control: 'small'
  })}
>
  <Button variant="outline">{'Small button'}</Button>
  <Button variant="outline" size="medium">
    {'Medium button'}
  </Button>
  <Button variant="outline">{'Small button'}</Button>
</Flex>
```

### Colour scheme

You can theme the buttons using `color` prop.

> **Important**
>
> Different button colour schemes have special purposes that are indicating specific
> actions to the users. [Check the guidelines below for details](#guidelines).

#### Default

```jsx
<Flex gap="spacingM">
  <Button color="default">{'Default'}</Button>
  <Button variant="outline">{'Default'}</Button>
  <Button variant="ghost">{'Default'}</Button>
</Flex>
```

#### Success/danger

```jsx
<Flex gap="spacingM" flow="column">
  <Flex gap="spacingM">
    <Button color="success">{'Success'}</Button>
    <Button color="danger">{'Danger'}</Button>
  </Flex>
  <Flex gap="spacingM">
    <Button variant="outline" color="success">
      {'Success'}
    </Button>
    <Button variant="outline" color="danger">
      {'Danger'}
    </Button>
  </Flex>
  <Flex gap="spacingM">
    <Button variant="ghost" color="success">
      {'Success'}
    </Button>
    <Button variant="ghost" color="danger">
      {'Danger'}
    </Button>
  </Flex>
</Flex>
```

### Button with icon

You can add left and right icons to the Button component using the `leftIcon` and `rightIcon` props respectively.

```jsx
<Flex gap="spacingL">
  <Button leftIcon={<SvgIcon iconName="filter" />}>{'Filter'}</Button>
  <Button rightIcon={<SvgIcon iconName="arrowRight" />} variant="outline">
    {'Next'}
  </Button>
  <Button
    size="small"
    rightIcon={<SvgIcon iconName="arrowRight" />}
    variant="outline"
  >
    {'Next'}
  </Button>
</Flex>
```

### Icon only button

Buttons may include an icon without a label. Icon only buttons work well in compact spaces.

> **Important**
>
> Please provide `aria-label` prop to support assistive technology (i.e. screen readers) or wrap the button with a [tooltip](https://next.wave-design-system.pages.dev/components/tooltip.md).

```jsx
<Flex gap="spacingL" flow="column">
  <Flex gap="spacingL">
    <Button withLoneIcon aria-label="Open settings">
      <SvgIcon iconName="settings" />
    </Button>
    <Tooltip content="Open user profile" placement="top">
      <Button withLoneIcon variant="outline">
        <SvgIcon iconName="user" />
      </Button>
    </Tooltip>
    <Button variant="ghost" withLoneIcon aria-label="Bookmark">
      <SvgIcon iconName="star" />
    </Button>
  </Flex>
  <Flex gap="spacingL">
    <Tooltip content="Go back" placement="top">
      <Button withLoneIcon variant="ghost" size="small">
        <SvgIcon iconName="arrowLeft" size="medium" />
      </Button>
    </Tooltip>
    <Button
      variant="ghost"
      size="small"
      color="danger"
      withLoneIcon
      aria-label="Delete item"
    >
      <SvgIcon iconName="trash" />
    </Button>
    <Tooltip content="View details" placement="top" delay={0}>
      <Button variant="ghost" size="xSmall" withLoneIcon>
        <SvgIcon iconName="info" />
      </Button>
    </Tooltip>
  </Flex>
  <Flex gap="spacingL">
    <Tooltip content="Close" placement="top">
      <Button withLoneIcon variant="ghost" size="small" shape="circle">
        <SvgIcon iconName="close" size="medium" />
      </Button>
    </Tooltip>
    <Button
      variant="ghost"
      size="small"
      shape="circle"
      color="success"
      withLoneIcon
      aria-label="Accept"
    >
      <SvgIcon iconName="check" />
    </Button>
    <Button
      variant="ghost"
      size="small"
      shape="circle"
      color="danger"
      withLoneIcon
      aria-label="Delete item"
    >
      <SvgIcon iconName="trash" />
    </Button>
  </Flex>
</Flex>
```

### Button states

#### Disabled

Each button may be displayed as disabled.

```jsx
<Flex gap="spacingL" flow="column">
  <Flex gap="spacingL">
    <Button color="success" disabled>
      {'Disabled'}
    </Button>
    <Button variant="outline" disabled>
      {'Disabled'}
    </Button>
    <Button
      variant="ghost"
      color="danger"
      withLoneIcon
      disabled
      aria-label="Delete"
    >
      <SvgIcon iconName="trash" />
    </Button>
  </Flex>
  <Box>
    <Button
      as="a"
      variant="outline"
      rightIcon={<SvgIcon iconName="arrowRight" />}
      href="https://volue.com"
      isDisabled
    >
      {'Go to volue.com'}
    </Button>
  </Box>
</Flex>
```

#### Loading

Pass the `isLoading` prop to show button in a loading state. By default, the button will show a [spinner](https://next.wave-design-system.pages.dev/components/spinner.md) and leave the button's width unchanged.

You can also pass the `loadingText` prop to show a [spinner](https://next.wave-design-system.pages.dev/components/spinner.md) and the loading text.

```jsx
<Flex gap="spacingL">
  <Button isLoading>{'Send'}</Button>
  <Button variant="outline" isLoading loadingText="Submitting…">
    {'Submit'}
  </Button>
</Flex>
```

### As link

Elements that are visually equivalent to buttons but change the URL and link to a new experience should be rendered as HTML anchor tags. Provide an `as` prop, and the button will render as an anchor tag.

> **Tip**
>
> `as` prop allows you to change the component to a different HTML tag or custom component (so called polymorphism).
>
> This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.
> You can now pass extra props to the underlying `<a>` element such as `href` etc. and it's perfectly type-safe 🎉

```jsx
<Button
  as="a"
  variant="outline"
  rightIcon={<SvgIcon iconName="arrowRight" />}
  href="https://volue.com"
  target="_blank"
>
  {'Go to volue.com'}
</Button>
```

---

## API reference

| Name           | Type                                                      | Default     | Description                                                                                                                                                                                                                                                                                                                              | Required |
| -------------- | --------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| `as`           | `keyof JSX.IntrinsicElements \| React.ComponentType<any>` | `button`    | Change the component to a different HTML tag or custom component. This will merge the original component props with the props of the supplied element/component and change the underlying DOM node.   For more details, read our [Composition](https://next.wave-design-system.pages.dev/get-started/composition.md#polymorphism) guide. |          |
| `css`          | `StitchesCss`                                             |             | Apply styles directly to a component in a similar way how you would define inline styles. Wave uses [Stitches](https://stitches.dev/) under the hood with a fully-typed API and support for features like tokens, media queries, or variants.                                                                                            |          |
| `variant`      | `"strong" \| "outline" \| "ghost"`                        | `"strong"`  | Visual variant of the button.                                                                                                                                                                                                                                                                                                            |          |
| `size`         | `"medium" \| "small" \| "xSmall" \| "xxSmall"`            |             | The size of the button. `xSmall` and `xxSmall` are only available when `withLoneIcon` prop is provided.                                                                                                                                                                                                                                  |          |
| `color`        | `"default" \| "success" \| "danger" \| "inverse"`         | `"default"` | The colour of the button.                                                                                                                                                                                                                                                                                                                |          |
| `leftIcon`     | `React.ReactElement`                                      |             | If added, the button will show an icon before the button's label.                                                                                                                                                                                                                                                                        |          |
| `rightIcon`    | `React.ReactElement`                                      |             | If added, the button will show an icon after the button's label.                                                                                                                                                                                                                                                                         |          |
| `withLoneIcon` | `boolean`                                                 | `false`     | Set `withLoneIcon` to `true`, when you only want to render an icon inside the button.                                                                                                                                                                                                                                                    |          |
| `shape`        | `"default" \| "circle"`                                   | `"default"` | When `withLoneIcon` is `true`, button can have additional `circle` shape.                                                                                                                                                                                                                                                                |          |
| `isLoading`    | `boolean`                                                 | `false`     | When `true`, the button will show a spinner and be disabled.                                                                                                                                                                                                                                                                             |          |
| `loadingText`  | `string`                                                  |             | The label to show in the button when `isLoading` is `true`. If no text is passed, it only shows the spinner.                                                                                                                                                                                                                             |          |
| `isDisabled`   | `boolean`                                                 | `false`     | When `true`, the button will be disabled, preventing the user from interacting with it.                                                                                                                                                                                                                                                  |          |
| `isActive`     | `boolean`                                                 | `false`     | When `true`, the button will be styled in its active state.                                                                                                                                                                                                                                                                              |          |
| `isNarrow`     | `boolean`                                                 | `false`     | If `true`, the button will take up less space on the sides.                                                                                                                                                                                                                                                                              |          |
