---
title: Button
description: "Text and icon buttons in the styles the game uses: metal and tile, each with an orange or white label."
---

<Component path="button/playground" />

## Installation

```bash
npx shadcn@latest add https://osrsui.com/r/button.json
```

## Variants and states

| Variant | Use for |
| --- | --- |
| `metal` (default) | Actions in modern windows (View DPS, Collection Log headers) |
| `tile` | Quantity rows and toggles (bank, World Switcher); turns red while `aria-pressed` |
| `stone` | Older interfaces |

For window close and menu buttons use [Window](/components/window); for settings categories, [Nav List](/components/nav-list).

To show a state without interacting, set `data-hover` or `aria-pressed` on the button.

## Tone

`tone="white"` swaps the orange label for a white one. On `metal` the label is white at rest as well as on hover (Collection Log, Combat Achievements). On `tile` it gives the Account panel's behaviour: a white label that dims on hover, with no red pressed state.

`tone="positive"` and `tone="destructive"` give a green or red label that keeps its colour in every state. Use them for a confirm / cancel pair (trade Accept / Decline, minigame Ready / Leave), keeping both buttons the same variant and width, and for a lone destructive action ("Yes" to destroy, "Delete your PIN").

```tsx
<Button tone="positive">Accept</Button>
<Button tone="destructive">Decline</Button>
```

## Sizes

Text and icon sizes share heights (game pixels, scaled by `--osrs-px`), so a row of text and icon buttons lines up.

| Text size | Icon size | Height |
| --- | --- | --- |
| `sm` | `icon-sm` | 26 |
| `default` | `icon` | 36 |
| `lg` | `icon-lg` | 44; long labels wrap to two lines |

## Usage

```tsx
import { Button } from "@/components/ui/button"
import { bankSprites } from "@/components/ui/bank-sprites"

<Button>Deposit inventory</Button>
<Button size="sm">Less <span className="text-[var(--osrs-orange)]">info</span></Button>
<Button variant="tile" tone="white" tooltip="Bond Pouch">Bond Pouch</Button>
<Button variant="tile" aria-pressed={qty === "All"} onClick={() => setQty("All")}>All</Button>

{/* Icon buttons: put any sprite (or SVG) inside and always give an aria-label */}
<Button variant="tile" size="icon" aria-label="Deposit inventory">
  <bankSprites.depositInventory />
</Button>
```

## Notes

- Toggle buttons: set `aria-pressed` and the button shows its pressed sprite.
- Non-sprite SVG icons (e.g. lucide) take the text colour and get the game's 1px drop shadow.
- Use the `render` prop to render a link: `<Button render={<a href="/bank" />}>Bank</Button>`.
