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

## Import

```js
import { Button } from '@gemini-suite/vera-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

Vera 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

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

```js
import { applySizes } from '@gemini-suite/vera-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>
```

### Color scheme

You can theme the buttons using `color` prop.

<Callout variant="important">

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

</Callout>

#### Accent (default)

```jsx
<Flex gap="spacingM">
  <Button color="accent">{'Accent'}</Button>
  <Button variant="outline">{'Accent'}</Button>
  <Button variant="ghost">{'Accent'}</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>
```

#### Inverse (white)

```jsx
<Flex
  gap="spacingM"
  css={{ backgroundColor: '$backgroundNeutralContrast', padding: '$spacingS' }}
>
  <Button color="inverse">{'Inverse'}</Button>
  <Button variant="outline" color="inverse">
    {'Inverse'}
  </Button>
  <Button variant="ghost" color="inverse">
    {'Inverse'}
  </Button>
</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.

<Callout variant="important">

Please provide `aria-label` prop to support assistive technology (i.e. screen readers) or wrap the button with a [tooltip](/components/tooltip).

</Callout>

```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://geminisuite.com"
      isDisabled
    >
      {'Go to geminisuite.com'}
    </Button>
  </Box>
</Flex>
```

#### Loading

Pass the `isLoading` prop to show button in a loading state. By default, the button will show a [spinner](/components/spinner) and leave the button's width unchanged.

You can also pass the `loadingText` prop to show a [spinner](/components/spinner) 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.

<Callout variant="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 🎉

</Callout>

```jsx
<Button
  as="a"
  variant="outline"
  rightIcon={<SvgIcon iconName="arrowRight" />}
  href="https://geminisuite.com"
  target="_blank"
>
  {'Go to geminisuite.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](/get-started/composition#polymorphism) guide. |          |
| `css`          | `StitchesCss`                                             |             | Apply styles directly to a component in a similar way how you would define inline styles. Vera 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`        | `"accent" \| "success" \| "danger" \| "inverse"`          | `"accent"`  | The color 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.                                                                                                                                                                                                                                  |          |

---

## Guidelines

### Variants

Different button variants have special purposes that are indicating specific actions to the users.
Each button type should represent correct actions consistently, considering their hierarchy and emphasis.

<SpecTable columns="auto 1fr" titles={['Button type', 'Purpose']}>
  <div>
    <InlineCode>Primary</InlineCode>
  </div>
  <div>
    The primary button serves as a main call-to-action on the layout. It's
    important to keep its appearance to one time per screen to lead users
    attention correctly. If the user have to choose between primary and
    secondary action, consider using outline button or ghost button for the
    secondary action.
  </div>
  <div>
    <InlineCode>Secondary</InlineCode>
  </div>
  <div>
    This type of button can be used as an alternative to the primary button if
    the actions requires less focus or attention. Secondary buttons should be
    used in tandem with a primary button.
  </div>
  <div>
    <InlineCode>Ghost</InlineCode>
  </div>
  <div>
    This type of button, similarly to the outline button, can be used for
    less-pronounced actions. Since ghost buttons don’t have a container, they
    don’t distract from nearby content.
  </div>
  <div>
    <InlineCode>Danger</InlineCode>
  </div>
  <div>
    Such buttons are used for an indication of negative actions or post-effects
    of actions (action such as "Remove" or "Delete"). They're coming in three
    styles: primary, secondary, and ghost.
  </div>
  <div>
    <InlineCode>Success</InlineCode>
  </div>
  <div>
    Success buttons are indicating positive actions or post-effects of actions.
    They're also coming in three styles: primary, secondary, and ghost.
  </div>
</SpecTable>

### Button sizes

<SpecTable columns="auto 1fr" titles={['Button size', 'Use case']}>
  <div>
    <InlineCode>Large 48px/3rem</InlineCode>
  </div>
  <div>This size is used for visually emphasising important actions.</div>
  <div>
    <InlineCode>Medium 40px/2.5rem</InlineCode>
  </div>
  <div>
    This size is used by default for primary page actions and other standalone
    actions.
  </div>
  <div>
    <InlineCode>Small 28px/1.75rem</InlineCode>
  </div>
  <div>
    Smaller buttons are used in case when there's not enough space for a default
    button, like in data tables or complex dashboards.
  </div>
</SpecTable>

### Alignment

Alignment rules will help you understand how to align your buttons based on the context of the interface.

<SpecTable columns="auto 1fr" titles={['Alignment', 'Use case']}>
  <div>
    <InlineCode>Left side</InlineCode>
  </div>
  <div>
    <Link href="/guides/layouts#one-page-form">One-page forms</Link>, and nested
    buttons in components like tiles or table lists.
  </div>
  <div>
    <InlineCode>Right side</InlineCode>
  </div>
  <div>
    Notification toasters, modal windows, popups, inline field buttons, header
    above the data tables,{' '}
    <Link href="/guides/layouts#form-in-a-stepper">form in a stepper</Link>, and
    single-button dialogs.
  </div>
  <div>
    <InlineCode>Center</InlineCode>
  </div>
  <div>Mobile resolutions, features on maps.</div>
</SpecTable>

### Hierarchy

Visual hierarchy in the UI is crucial. It helps to find the needed elements and information efficiently.

Having a single high-emphasis button clarifies that other buttons are less important in the hierarchy.

At the same time, the layout can also contain more than one button at a time.
A high-emphasis button can be followed by medium- and low-emphasis buttons that perform less critical actions.

### Text labels

Text labels are communicating the action that will be performed when the user interacts with the button.
Text labels in buttons must be clear, not long as poems, and predictable.

### Buttons with icons

A button can include an icon to clarify and call attention to a specific action.

- Icons within the buttons should be `16px/1rem` by `16px/1rem`
- Use icons that are directly related to the action that the user is taking

The alignment of icons within buttons depends on the layout and the context of where these elements are used.

### Icon-only buttons

In some cases, an icon-only button can be used in the layout. Usually, such practice is used for simple meaning actions.

An example of a correct replacement of the text labels with icons.

<Callout
  variant="important"
  title="Don't replace a complicated text label with a single icon
"
>
  Not all actions can be replaced with an icon.
</Callout>

### Button groups

You can group together buttons related by function.
A button group is a series of buttons laid out next to each other, joined together to create one continuous UI.

Button groups are useful to create "toggles" that allow to switch between two or more options.
This can be used to filter content for example.

### Danger and success buttons

Danger and success buttons are available in three types: primary, success, ghost. The use of each depends on the level of emphasis of the action.

### Map controllers

A lot of Volume products are operating using maps.
Follow the guide below to make sure that your map controlling buttons are consistent and convenient.

<Flex className="mBm mLm--l">
  <Box className="label label--circular fill-purple100">1</Box>
  <Box>"Zoom in" controller</Box>
</Flex>
<Flex className="mBm mLm--l">
  <Box className="label label--circular fill-purple100">2</Box>
  <Box>"Zoom out" controller</Box>
</Flex>
<Flex className="mBm mLm--l">
  <Box className="label label--circular fill-purple100">3</Box>
  <Box>"My location" controller</Box>
</Flex>

A recommendation for the icon of the [My location](#map-controllers) controller.
