---
title: Button
description: Use Button when people need to start, confirm, or submit an action.
version: 11.17.0
generatedAt: 2026-11-05T09:55:46.061Z
checksum: fff89b3d5a1fc53a52c64d0cd511538755775f5c820cb471c529341330af3ff9
---

# Button

## Description

Use Button to start, confirm, or submit an action, such as "Add account" or "Save changes". Use [Anchor](/web/components/anchor) to navigate to another page or section.

## Import

```tsx
import { Button } from '@dnb/eufemia'
```

## Accessibility

Buttons support keyboard interaction: Tab moves focus, and Enter or Space activates the button. Keep the focus indicator visible and use a label that describes the action.

For buttons without visible text, follow the [icon-only button guidance](/web/components/button/demos/#icon-button).

## Relevant links

- [Figma](https://www.figma.com/design/cdtwQD8IJ7pTeE45U148r1/%F0%9F%92%BB-Eufemia---Web?node-id=339-154)
- [Source code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-eufemia/src/components/button)
- [Docs code](https://github.com/dnbexperience/eufemia/tree/main/packages/dnb-design-system-portal/src/docs/web/components/button)


## Related components

Button is part of the [Actions](/web/components/overview/#actions) category. More components in this category:

- [Help button](/web/components/help-button/) – when a short explanation should be available next to a label or control.
- [Menu](/web/components/menu/) – when people need to choose from a small list of actions or links.
- [Vipps wallet button](/web/patterns-and-extensions/vipps-wallet-button/) – A branded Vipps wallet call-to-action button extension.


## Typography

DNB button labels use DNB Sans Text Regular, matching the Eufemia Web
Figma library. This applies to primary, secondary, tertiary and unstyled
buttons. Built-in selection controls, navigation and clickable file names
also retain Regular. Other brands retain their existing typography.
The text font is shared with other interface content; Display is reserved
for expressive headlines.

DNB labels use normalized font metrics and no additional upward adjustment.
Sbanken retains its existing label adjustment for Roboto. The font weight
and vertical alignment are separate choices; changing the weight is not a
centering correction.


## Demos

### Choose a variant

Choose the visual emphasis to match the importance of the action.


```tsx
render(<Flex.Container gap="medium" align="center">
      <Button text="Primary" />
      <Button text="Secondary" variant="secondary" />
      <Button text="Tertiary" variant="tertiary" icon="chevron_right" />
    </Flex.Container>)
```


- **Primary:** the main action. Use at most one in a given context.
- **Secondary:** other actions alongside the primary action.
- **Tertiary:** a less prominent action with an icon.

Expand **Code** below each example to edit it or copy the implementation.

### Text buttons

Use a short label that describes the action. Set `variant="secondary"` for a secondary action.

#### Primary button


```tsx
render(<Button text="Primary button with text only" data-visual-test="button-primary" />)
```


#### Secondary button


```tsx
render(<Button variant="secondary" data-visual-test="button-secondary">
      Secondary button with text only
    </Button>)
```


### Buttons with icons

Set `icon` to add an icon. Icons appear on the right by default. Use `iconPosition="left"` to place one before the label.

#### Primary button with icon


```tsx
render(<Button text="Primary button with icon" icon="chevron_right" />)
```


#### Primary button with icon on left


```tsx
render(<Button iconPosition="left" icon="chevron_left">
      Primary button with icon on left
    </Button>)
```


### Tertiary button

Use `variant="tertiary"` with an icon for a less prominent action. The label can be plain text or a React element.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button variant="tertiary" text="Back" iconPosition="left" icon="chevron_left" data-visual-test="button-tertiary" />
      <Button variant="tertiary" text={<span>Previous step</span>} iconPosition="left" icon="chevron_left" />
    </Flex.Horizontal>)
```


#### Icon above the label

Use `iconPosition="top"` to place the icon above the label.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="large" align="center">
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Default</P>
        <Button variant="tertiary" iconPosition="top" icon="close" text="Close" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Large</P>
        <Button variant="tertiary" iconPosition="top" icon="close" text="Close" size="large" />
      </Flex.Stack>
    </Flex.Horizontal>)
```


#### Wrapping long labels

Wrapping is opt-in because button labels should be short and easy to scan. If a label is long enough to need a line break, consider shortening it or using a different component that better fits the content and interaction.

Set `wrap` to allow the label to span multiple lines. The icon stays aligned with the top of the text.


```tsx
render(<div style={{
  maxWidth: '20rem'
}}>
      <Button wrap variant="tertiary" text="Back to the overview of your accounts and recent transactions" icon="chevron_left" iconPosition="left" />
    </div>)
```


### Icon button

**Use buttons with visible text by default.** Only use an icon-only button when the action and what it affects are immediately clear to your users, without a tooltip. If there is any doubt, keep the text label.

#### Choose an icon that fits the context

Use an existing [Eufemia icon](/collections/icons) and keep its meaning consistent throughout your application. Even in the contexts below, only omit the text label if the action and its scope are unambiguous to your users.

|                   Icon                   | Action | Context to check                    |
| :--------------------------------------: | ------ | ----------------------------------- |
| <IconPrimary icon="close" aria-hidden /> | Close  | In the dialog or panel it closes.   |
| <IconPrimary icon="trash" aria-hidden /> | Delete | Beside the attachment it deletes.   |
| <IconPrimary icon="loupe" aria-hidden /> | Search | Beside a labeled search field.      |
| <IconPrimary icon="edit" aria-hidden />  | Edit   | In the row of the item it edits.    |
|  <IconPrimary icon="add" aria-hidden />  | Add    | In a list that shows what is added. |

#### Use visible text when

- **The action is important or difficult to undo**, such as "Send payment" or "Delete account". A trash icon does not explain the scope of a deletion.
- **The icon could mean several things.** A plus could mean add an item, create an account, or zoom in. Use a label such as "Add account".
- **People need a tooltip to understand the action.** Tooltips can help, but should not be the only explanation, especially on touch screens.

Limited space, including on smaller screens, is not enough reason to remove a text label.

#### Name the action

Every icon-only button needs an accessible name. Describe the action, such as "Delete invoice.pdf", rather than the shape, such as "Trash icon".

Set `aria-label` and add a matching `tooltip` for hover and keyboard focus. A `tooltip` alone does not provide an accessible name in Eufemia.

```tsx
<Button icon="close" aria-label="Close" tooltip="Close" />
```

Alternatively, `title` supplies the accessible name automatically for icon-only buttons.

The labels above the buttons identify the sizes and states.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="large" align="center">
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Disabled</P>
        <Button title="Open calendar" icon="calendar" disabled />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Default</P>
        <Button title="Open calendar" icon="calendar" data-visual-test="button-icon" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Small</P>
        <Button title="Add item" icon="add" size="small" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Large</P>
        <Button title="Help" icon={question} size="large" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Error</P>
        <Button title="Help" icon={question} status="error" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Tertiary</P>
        <Button title="Help" size="large" icon={question} variant="tertiary" data-visual-test="button-icon-tertiary" />
      </Flex.Stack>
    </Flex.Horizontal>)
```


<span id="variants-and-sizes" />

### Sizes

Use `size` to set the button dimensions.

#### Primary button sizes

Use `default` or `large` for primary buttons.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button text="Default" />
      <Button text="Large" size="large" />
      <Button text="Default with icon" icon="chevron_right" />
      <Button text="Large with icon" size="large" icon="chevron_right" />
    </Flex.Horizontal>)
```


#### Secondary button sizes

Use `default` or `large` for secondary buttons.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button text="Default" variant="secondary" />
      <Button text="Large" size="large" variant="secondary" />
      <Button text="Default with icon" icon="chevron_right" variant="secondary" />
      <Button text="Large with icon" size="large" icon="chevron_right" variant="secondary" />
    </Flex.Horizontal>)
```


#### Tertiary button sizes

Use `default` (recommended) or `large` for tertiary buttons with text.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button text="Default" icon="chevron_right" variant="tertiary" />
      <Button text="Large" size="large" icon="chevron_right" variant="tertiary" />
      <Button text="Notifications" icon="bell" iconPosition="top" variant="tertiary" />
    </Flex.Horizontal>)
```


#### Icon button sizes

Icon-only buttons support `small`, `medium`, `default` and `large`, including the tertiary variant. When `size` is omitted, an icon-only button uses `medium`.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="large" align="center">
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Small</P>
        <Button title="Add item" icon="add" size="small" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Medium (default)</P>
        <Button title="Add item" icon="add" size="medium" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Default</P>
        <Button title="Add item" icon="add" size="default" />
      </Flex.Stack>
      <Flex.Stack layoutEngine="css" element="div" gap="x-small" align="center">
        <P size="small">Large</P>
        <Button title="Add item" icon="add" size="large" />
      </Flex.Stack>
    </Flex.Horizontal>)
```


`size` controls the button dimensions, while `iconSize` controls the icon dimensions. For example, this small tertiary button is `1.5rem` square (24 px at the default root font size), with a `1rem` (16 px) icon:

```tsx
<Button
  variant="tertiary"
  size="small"
  icon="add"
  iconSize="default"
  title="Add attachment"
/>
```

### Anchor button

Set `href` when navigation needs the visual emphasis of a button. Button renders an anchor element in this case. Prefer [Anchor](/web/components/anchor) for ordinary links.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button text="View accounts" href="/web/components/button/demos" iconPosition="right" icon="chevron_right" />
      <Button variant="secondary" text="Open in a new tab" href="/web/components/button/demos" target="_blank" />
      <Button href="/web/components/button/demos" title="Go to the Button documentation" icon="chevron_right" size="default" />
    </Flex.Horizontal>)
```


### Disabled buttons

Set `disabled` to make an action unavailable. Prefer keeping actions available where possible. A disabled button alone does not explain what the user needs to do next.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button text="Primary" disabled />
      <Button text="Secondary" variant="secondary" disabled />
      <Button text="Tertiary" variant="tertiary" icon="chevron_right" disabled />
      <Button title="Open calendar" icon="calendar" disabled />
      <Button text="Link button" href="/web/components/button/demos" target="_blank" disabled />
    </Flex.Horizontal>)
```


### Error state

Set `status="error"` to indicate an error state. When an action fails, also explain the problem and how to recover. A color change alone is not enough.


```tsx
render(<Flex.Horizontal layoutEngine="css" gap="medium" align="center">
      <Button text="Primary" status="error" data-visual-test="button-error-primary" />
      <Button text="Secondary" variant="secondary" status="error" data-visual-test="button-error-secondary" />
      <Button text="Tertiary" icon="chevron_right" variant="tertiary" status="error" data-visual-test="button-error-tertiary" />
      <Button title="Primary icon button error" variant="primary" icon={question} size="default" status="error" />
      <Button title="Secondary icon button error" icon={question} size="default" status="error" />
    </Flex.Horizontal>)
```


### Button on dark surface

Use [Section](/web/components/section/demos/#dark-surface) or [Theme.Context](/web/styling-and-themes/brands-and-dark-mode/theme#surface-property) with `surface="dark"` to provide dark surface context to supporting components.


```tsx
render(<Section innerSpace={{
  block: true
}} surface="dark">
      <Flex.Horizontal layoutEngine="css" gap="medium" align="center" style={{
    backgroundColor: 'inherit'
  }}>
        <Button data-visual-test="button-primary-on-dark">
          Primary button
        </Button>
        <Button data-visual-test="button-secondary-on-dark" variant="secondary">
          Secondary button
        </Button>
        <Button data-visual-test="button-tertiary-on-dark" variant="tertiary" iconPosition="left" icon="chevron_left">
          Tertiary button
        </Button>
        <Button data-visual-test="button-tertiary-icon-on-dark" variant="tertiary" icon="bell" title="Notifications" />
      </Flex.Horizontal>
    </Section>)
```


### Custom button content

Use `customContent` when the standard label and icon do not cover the content you need. You are responsible for aligning custom content.


```tsx
render(<Button icon="close" iconPosition="right" text="Button with custom content" customContent={<IconPrimary icon="check" right="small" />} />)
```


### Button with custom SVG

A custom SVG can be part of the button's children. Give meaningful graphics an accessible name and hide decorative graphics from assistive technology. The button still needs a meaningful accessible name.


```tsx
render(<Button variant="secondary">
          Button with SVG <VippsLogo />
        </Button>);
```

<!-- eufemia-properties-usage:start -->
Some properties provide flexibility for specific integrations. Follow the component's usage guidance. Customizations beyond the documented patterns need a use case approved by DNB UX. [Read about intended use and customization](/web/styling-and-themes/configuration/component-properties/#intended-use-and-customization).
<!-- eufemia-properties-usage:end -->

## Properties


```json
{
  "props": {
    "type": {
      "doc": "The type HTML attribute. Defaults to `button` to prevent accidental form submissions.",
      "type": [
        "\"button\"",
        "\"reset\"",
        "\"submit\""
      ],
      "status": "optional"
    },
    "text": {
      "doc": "The content of the button can be a string or a React Element.",
      "type": [
        "string",
        "React.ReactNode"
      ],
      "status": "optional"
    },
    "aria-label": {
      "doc": "Required if there is no text in the button. If `text` and `children` are `undefined`, setting the `title` property will automatically set `aria-label` with the same value.",
      "type": "string",
      "status": "optional"
    },
    "title": {
      "doc": "Required if there is no text in the button. If `text` and `children` are `undefined`, setting the `title` property will automatically set `aria-label` with the same value. Accepts `ReactNode`. If a JSX element is provided, it will be converted to a plain string using `convertJsxToString` — only static text content is extracted. Custom components that don't render static children will result in an empty string.",
      "type": "string",
      "status": "optional"
    },
    "variant": {
      "doc": "Defines the kind of button. Possible values are `primary`, `secondary` and `tertiary`. Defaults to `primary` (or `secondary` if icon only). The `tertiary` button is normally used together with an icon. Use default or large for tertiary buttons with text; icon-only tertiary buttons support all sizes.",
      "type": [
        "\"primary\"",
        "\"secondary\"",
        "\"tertiary\"",
        "\"unstyled\""
      ],
      "status": "optional"
    },
    "size": {
      "doc": "The size of the button. There is `default`, `small`, `medium` and `large`. Use default or large for tertiary buttons with text; icon-only tertiary buttons also support small and medium. Changing the size mainly affects spacing, but the large tertiary button also has a larger font size.",
      "type": [
        "\"default\"",
        "\"small\"",
        "\"medium\"",
        "\"large\""
      ],
      "status": "optional"
    },
    "icon": {
      "doc": "To be included in the button. [Primary Icons](/collections/icons) can be set as a string (e.g. `icon=\"chevron_right\"`), other icons should be set as React elements. For the `tertiary` button an icon is basically required for accessibility reasons (unless you explicitly turn it off with `icon={false}`).",
      "type": [
        "string",
        "React.ReactNode"
      ],
      "status": "optional"
    },
    "iconPosition": {
      "doc": "Position of icon inside the button. Set to `left` or `right`. Tertiary button variant also supports `top`. Defaults to `right` if not set.",
      "type": [
        "\"left\"",
        "\"right\"",
        "\"top\""
      ],
      "status": "optional"
    },
    "iconSize": {
      "doc": "Define icon width and height. Defaults to `16px`.",
      "type": "string",
      "status": "optional"
    },
    "selected": {
      "doc": "Only for icon buttons. If true, use the style for a selected icon button. Defaults to `false`.",
      "type": "boolean",
      "status": "optional"
    },
    "href": {
      "doc": "If you want the button to behave as a link. Use with caution! A link should normally visually be a link and not a button.",
      "type": "string",
      "status": "optional"
    },
    "target": {
      "doc": "When button behaves as a link. Used to specify where to open the linked document, specified by `href`. Possible values are `_self`, `_blank`, `_parent` and `_top`.",
      "type": [
        "\"_self\"",
        "\"_blank\"",
        "\"_parent\"",
        "\"_top\""
      ],
      "status": "optional"
    },
    "rel": {
      "doc": "When button behaves as a link. Used to specify the relationship between a linked resource and the current document. Examples (non-exhaustive list) of values are `nofollow`, `search`, and `tag`.",
      "type": "string",
      "status": "optional"
    },
    "to": {
      "doc": "Use this property only if you are using a router Link component as the `element` that uses the `to` property to declare the navigation url.",
      "type": "string",
      "status": "optional"
    },
    "wrap": {
      "doc": "Set to `true` to allow the label to wrap onto multiple lines when it reaches the available width. Defaults to `false` because button labels should be short and easy to scan. If a label needs a line break, consider shortening it or using a different component that better fits the content and interaction.",
      "type": "boolean",
      "status": "optional"
    },
    "stretch": {
      "doc": "Set it to `true` in order to stretch the button to the available space. Defaults to `false`.",
      "type": "boolean",
      "status": "optional"
    },
    "bounding": {
      "doc": "Set it to `true` in order to extend the bounding box (above the visual button background). You may also look into the HTML class `dnb-button__bounding` if it needs some CSS customization in order to get the particular button right for your use-case.",
      "type": "boolean",
      "status": "optional"
    },
    "element": {
      "doc": "Only meant to be used for special use cases. Defaults to `button` or `a` depending if href is set or not.",
      "type": "string",
      "status": "optional"
    },
    "customContent": {
      "doc": "If you need to inject completely custom markup (React Element) into the button component. You have then to handle alignment and styling by yourself.",
      "type": "React.ReactNode",
      "status": "optional"
    },
    "skeleton": {
      "doc": "If set to `true`, an overlaying skeleton with animation will be shown.",
      "type": "boolean",
      "status": "optional"
    },
    "tooltip": {
      "doc": "Provide a string or a React Element to be shown as the tooltip content.",
      "type": [
        "string",
        "React.ReactNode"
      ],
      "status": "optional"
    },
    "status": {
      "doc": "Set it to either `status=\"error\"` or a text with a status message. The style defaults to an error message. You can use `true` to only get the status color, without a message.",
      "type": [
        "\"error\"",
        "\"information\"",
        "boolean"
      ],
      "status": "optional"
    },
    "statusState": {
      "doc": "Defines the state of the status. Can be `error`, `warning`, `information`, `success` or `marketing`. Defaults to `error`.",
      "type": [
        "\"error\"",
        "\"warning\"",
        "\"information\"",
        "\"success\"",
        "\"marketing\""
      ],
      "status": "optional"
    },
    "statusProps": {
      "doc": "Use an object to define additional FormStatus properties.",
      "type": "object",
      "status": "optional"
    },
    "globalStatus": {
      "doc": "The [configuration](/web/components/global-status/properties/#configuration-object) used for the target [GlobalStatus](/web/components/global-status).",
      "type": "object",
      "status": "optional"
    },
    "[Space](/web/layout-and-typography/layout/space/properties)": {
      "doc": "Spacing properties like `top` or `bottom` are supported.",
      "type": [
        "string",
        "object"
      ],
      "status": "optional"
    }
  },
  "usageGuidance": "Some properties provide flexibility for specific integrations. Follow the component's usage guidance. Customizations beyond the documented patterns need a use case approved by DNB UX. [Read about intended use and customization](/web/styling-and-themes/configuration/component-properties/#intended-use-and-customization)."
}
```


### Unstyled variant

In cases where it makes sense to use the button component, but with very different styles, you can use `unstyled` as a variant. For now, it is only meant to be used internally.

## Events


```json
{
  "props": {
    "onClick": {
      "doc": "Will be called on a click event. Returns an object with the native event: `{ event }`.",
      "type": "function",
      "status": "optional"
    }
  }
}
```
