> For AI agents: the complete documentation index is available at /ooui-react/en/llms.txt, the full documentation bundle is available at /ooui-react/en/llms-full.txt.

# Button

> [Source](https://github.com/BearBin1215/ooui-react/tree/main/src/widgets/Button) | [Original component](https://doc.wikimedia.org/oojs-ui/master/js/OO.ui.ButtonWidget.html "OO.ui.ButtonWidget")

The basic button component, and also the button base for [ToggleButton](/ooui-react/en/components/toggle-button/index.md), [PopupButton](/ooui-react/en/components/popup-button/index.md), [ButtonMenuSelectWidget](/ooui-react/en/components/button-menu-select/index.md) and other components.

## Basic usage

```tsx preview
import { useState } from "react";
import { Button } from "ooui-react";

function App() {
  const [count, setCount] = useState(0);

  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <Button onClick={() => setCount((n) => n + 1)}>Click me</Button>
      <span>Clicked {count} times</span>
    </div>
  );
}

export default App;
```

## Icons and indicators

`icon` takes an icon name (see [Icon](/ooui-react/en/components/icon/index.md)), `indicator` takes one of the four indicators (see [Indicator](/ooui-react/en/components/indicator/index.md)). They render on opposite ends of the label.

When the label is icon-only, turn on `invisibleLabel`: the label is visually hidden but kept as the accessible name, and `title` falls back to the label text when not given explicitly.

```tsx preview
import { Button } from "ooui-react";

function App() {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <Button icon="check">Done</Button>
      <Button icon="trash" flags="destructive">
        Delete
      </Button>
      <Button indicator="down">Expand</Button>
      <Button icon="search" invisibleLabel>
        Search
      </Button>
    </div>
  );
}

export default App;
```

## Flags and variants

`flags` affect color and icon tinting, `framed={false}` switches to the unframed form, and `active` marks a selected/activated state.

```tsx preview
import { Button } from "ooui-react";

function App() {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" }}>
      <Button>Default</Button>
      <Button flags="progressive">Continue</Button>
      <Button flags={["primary", "progressive"]}>Save</Button>
      <Button flags="destructive">Delete</Button>
      <Button framed={false} flags="destructive">
        Unframed delete
      </Button>
      <Button active>Active</Button>
    </div>
  );
}

export default App;
```

A framed button inverts as a whole when `primary`, active, or disabled, and the icon and indicator invert with it; otherwise it is tinted by the color flag in `flags`. The available color flags are `progressive`, `destructive`, `invert`, `error`, `warning` and `success`.

## As a link

Given `href`, the inner `<a>` becomes a navigable link and `target` chooses where it opens. `rel` defaults to `nofollow`; when using `target="_blank"` you should add `noopener` yourself.

```tsx preview
import { Button } from "ooui-react";

function App() {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <Button href="https://www.mediawiki.org">MediaWiki</Button>
      <Button href="https://www.mediawiki.org" target="_blank" rel={["nofollow", "noopener"]}>
        Open in a new tab
      </Button>
    </div>
  );
}

export default App;
```

:::warning Security note
This component does not sanitize `href`
 (it bypasses the original `OO.ui.isSafeUrl`
), and React does not block dangerous schemes such as `javascript:`
 at runtime either. **Links of untrusted origin (e.g. concatenated from user input) must have their protocol validated by you first**
, otherwise this is an XSS; when you want component-level sanitizing, use the exported `sanitizeUrl`
. 
:::
## Disabled

`disabled` outputs `oo-ui-widget-disabled` and `aria-disabled` (not the native `disabled`); the button then ignores clicks, its `tabindex` becomes `-1`, and `href` no longer takes effect. Inside a `ButtonGroup`, the group-level disabled state propagates to the buttons in it.

```tsx preview
import { Button } from "ooui-react";

function App() {
  return (
    <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
      <Button disabled>Disabled</Button>
      <Button icon="check" disabled>
        Disabled (with icon)
      </Button>
    </div>
  );
}

export default App;
```

## Focus and keyboard

- The focusable element is the inner `<a>`; the root `<span>` is not focusable. To focus the button manually, use `anchorRef` (the component `ref` points to the outer `<span>`).
- Enter / Space trigger `onClick`; `onKeyPress` prevents Space from scrolling the page whenever a click handler is present.
- The pressed state (`oo-ui-buttonElement-pressed`) is maintained by the component in JS: CSS has no keyboard-press pseudo-class, so keyboard press and release are handled by explicit event listeners. The `pressed` prop is OR-ed with it, for cases like "keep the button pressed while its associated menu is open".
- `title` and `accessKey` land on the inner `<a>`; when `title` is not given and the label is hidden it falls back to the label text, and when `accessKey` is present a key hint is appended to `title` (the chord text can be localized via [OOUIProvider](/ooui-react/en/guide/configuration.md#access-key-label)).

## API

| Prop                           | Description                                                                                                                  | Type                                      | Default        |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | -------------- |
| `children`                     | Button label                                                                                                                 | `ReactNode`                               | —              |
| `icon`                         | Leading icon name                                                                                                            | `string`                                  | —              |
| `indicator`                    | Trailing indicator                                                                                                           | `'up' \| 'down' \| 'clear' \| 'required'` | —              |
| `flags`                        | Extra flags (color and button-specific form)                                                                                 | `ButtonFlag \| ButtonFlag[]`              | `[]`           |
| `framed`                       | Whether it has a border                                                                                                      | `boolean`                                 | `true`         |
| `active`                       | Whether it is in the active state                                                                                            | `boolean`                                 | `false`        |
| `invisibleLabel`               | Label visually hidden (kept as accessible name)                                                                              | `boolean`                                 | `false`        |
| `disabled`                     | Whether disabled (incl. the owning `ButtonGroup`'s group disable)                                                            | `boolean`                                 | `false`        |
| `href`                         | Link target (written on the inner `<a>`)                                                                                     | `string`                                  | —              |
| `target`                       | Where the link opens                                                                                                         | `string`                                  | —              |
| `rel`                          | The inner `<a>`'s `rel` (an array is joined by spaces)                                                                       | `string \| string[]`                      | `['nofollow']` |
| `title`                        | Tooltip text for the inner `<a>`                                                                                             | `string`                                  | —              |
| `accessKey`                    | Access key                                                                                                                   | `string`                                  | —              |
| `tabIndex`                     | Tab order; `null` means the attribute is omitted                                                                             | `number \| null`                          | `0`            |
| `pressed`                      | Controlled pressed state (OR-ed with the internal press flow)                                                                | `boolean`                                 | —              |
| `onClick`                      | Click handler (also fired by Enter / Space)                                                                                  | `(ev: ButtonClickEvent) => void`          | —              |
| `anchorRef`                    | Ref to the inner `<a>` element                                                                                               | `Ref<HTMLAnchorElement>`                  | —              |
| `anchorProps`                  | Extra props for the inner `<a>`; `role`, `tabIndex`, `aria-disabled`, etc. are taken over by the component and take priority | `HTMLAttributes<HTMLAnchorElement>`       | —              |
| `iconProps` / `indicatorProps` | Extra props for the icon / indicator element                                                                                 | `object`                                  | —              |
| `...rest`                      | Native `span` props (`className`, `id`, `data-*`, `aria-*`, etc.) passed straight to the root                                | `HTMLAttributes<HTMLSpanElement>`         | —              |

`ButtonFlag` is `'progressive' | 'destructive' | 'invert' | 'error' | 'warning' | 'success' | 'primary' | 'safe' | 'back' | 'close'`; the first six decide tinting, the last four are button-specific form flags.
