---
title: Toolbar
description: Toolbars group formatting or view controls that affect a shared context, such as rich text editors, chart controls, or data tables.
category: Actions
---
import { meta as ToolbarMeta, Default } from '@/content/stories/toolbar';
import Canvas from '@/components/component-docs/canvas';
import Demo from '@/components/component-docs/demo';
export const config = {
dependencies: {
components: [Canvas, Demo],
scripts: [
'../../components/component-docs/demo.script.tsx',
'../../components/component-docs/canvas.script.tsx',
'../../components/component-docs/controls.script.tsx',
],
},
};
# Toolbar
Toolbars group formatting or view controls that affect a shared context, such as rich text editors, chart controls, or data tables.
## Try it
## Usage
Place toggle `RuiButton` children inside `RuiToolbar`. Use `RuiSeparator` to divide related control categories. Enable `exclusiveToggles` when only one toggle can be active.
```tsx
import { RuiToolbar } from '@ecopages/radiant-ui/toolbar';
import { RuiButton } from '@ecopages/radiant-ui/button';
import { RuiSeparator } from '@ecopages/radiant-ui/separator';
BIUS
```
## Custom markup
`` coordinates any light-DOM tree with focusable controls. The `RuiToolbar` helper stamps `[role="toolbar"]`; it is not required.
```tsx
import '@ecopages/radiant-ui/toolbar';
;
```
Toggle buttons need `data-toggle` and `aria-pressed`. The host updates `aria-pressed` on click.
## Exclusive toggles
Use `exclusiveToggles` for view modes where only one option (list vs grid) can be active at a time.
## Theming
Toolbar surfaces map to **semantic surface roles**, never Tailwind palette steps:
| Part | CSS roles |
| --- | --- |
| Bar (`rui-toolbar`) | `surface`, `border`, `rounded-container` |
| Pressed toggle (`rui-button--ghost` / `--outline[aria-pressed='true']`) | `background`, `on-background`, `shadow-sm` |
Geometry shares control tokens (`--size-control-*`, `--space-control-*`) with `RuiButton`. Override roles at the theme layer, not in component CSS.
## API
`RuiToolbar` is a custom element (``) rendering a `role="toolbar"` container. Place `RuiButton` toggles or other focusable controls as children.
### Attributes
| Attribute | Type | Default | Description |
| --- | --- | --- | --- |
| `label` | `string` | `''` | Accessible name for the toolbar region. |
| `exclusive-toggles` | `boolean` | `false` | Only one toggle button stays pressed at a time. |
### Light-DOM contract
| Target | Required | Host writes | Author owns |
| --- | --- | --- | --- |
| `button`, `a[href]`, `input`, `select`, `textarea`, `[tabindex]` | yes | roving `tabIndex` | control markup, `disabled` |
| `button[data-toggle][aria-pressed]` | for toggles | `aria-pressed` | initial `aria-pressed`, `data-toggle` |
Nested hosts: none.
### View helpers
| Component | Target stamped | Notes |
| --- | --- | --- |
| `RuiToolbar` | `[role="toolbar"]` with `data-ref="root"` | Place focusable controls as children. |
### CSS classes
Public BEM classes on the composed surface (documented via `@cssclass`):
| Class | Description |
| --- | --- |
| `.rui-toolbar` | Toolbar surface (`role="toolbar"`). |
Pressed-toggle styling applies to `rui-button--ghost` / `rui-button--outline` inside the toolbar (see Button). Toggles expose their state via `aria-pressed`.
`RuiSeparator` is a generic helper. In a toolbar, use `orientation="vertical"` to divide categories without adding a focus stop.
### Theme roles
| Part | CSS variables consumed |
| --- | --- |
| Bar | `--surface`, `--border` |
| Pressed toggle | `--background`, `--on-background`, `--shadow-sm` |
| Focus ring | `--focus-ring` |
## Accessibility
- Toolbar renders with `role="toolbar"` and an accessible name from `label`.
- Toggle buttons expose `aria-pressed` for their on/off state.
- Arrow keys move between toolbar controls when focus is inside the toolbar; separators are skipped.