adev/src/content/guide/aria/toolbar.md
A container for grouping related controls and actions with keyboard navigation, commonly used for text formatting, toolbars, and command panels.
<docs-tab-group> <docs-tab label="Basic"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/basic/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/basic/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/basic/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/basic/app/app.css"/> </docs-code-multifile> </docs-tab> <docs-tab label="Material"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.css"/> </docs-code-multifile> </docs-tab> <docs-tab label="Retro"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.css"/> </docs-code-multifile> </docs-tab> </docs-tab-group>Toolbar works best for grouping related controls that users access frequently. Consider using toolbar when:
Avoid toolbar when:
Angular's toolbar provides a fully accessible toolbar implementation with:
Horizontal toolbars organize controls from left to right, matching the common pattern in text editors and design tools. Arrow keys navigate between widgets, maintaining focus within the toolbar until users press Tab to move to the next page element.
<docs-tab-group> <docs-tab label="Basic"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/basic/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/basic/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/basic/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/basic/app/app.css"/> </docs-code-multifile> </docs-tab> <docs-tab label="Material"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/basic/material/app/app.css"/> </docs-code-multifile> </docs-tab> <docs-tab label="Retro"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/basic/retro/app/app.css"/> </docs-code-multifile> </docs-tab> </docs-tab-group>Vertical toolbars stack controls top to bottom, useful for side panels or vertical command palettes. Up and down arrow keys navigate between widgets.
<docs-tab-group> <docs-tab label="Basic"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/vertical/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/vertical/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/vertical/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/vertical/app/app.css"/> </docs-code-multifile> </docs-tab> <docs-tab label="Material"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/vertical/material/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/vertical/material/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/vertical/material/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/vertical/material/app/app.css"/> </docs-code-multifile> </docs-tab> <docs-tab label="Retro"> <docs-code-multifile preview hideCode path="adev/src/content/examples/aria/toolbar/src/vertical/retro/app/app.ts"> <docs-code header="app.ts" path="adev/src/content/examples/aria/toolbar/src/vertical/retro/app/app.ts"/> <docs-code header="app.html" path="adev/src/content/examples/aria/toolbar/src/vertical/retro/app/app.html"/> <docs-code header="app.css" path="adev/src/content/examples/aria/toolbar/src/vertical/retro/app/app.css"/> </docs-code-multifile> </docs-tab> </docs-tab-group>Widget groups organize related controls that work together, such as text alignment options or formatting toggles. Groups maintain roving tabindex navigation while presenting the appropriate semantic structure to assistive technologies.
In the examples above, the alignment buttons are wrapped in ngToolbarWidgetGroup with role="radiogroup". Selection is decoupled from the toolbar container, allowing you to manage state using Angular signals or custom directives:
<!-- Mutually exclusive radio group -->
<div ngToolbarWidgetGroup role="radiogroup" aria-label="Alignment">
<button
ngToolbarWidget
role="radio"
type="button"
[attr.aria-checked]="alignment() === 'left'"
(click)="alignment.set('left')"
>
Left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
[attr.aria-checked]="alignment() === 'center'"
(click)="alignment.set('center')"
>
Center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
[attr.aria-checked]="alignment() === 'right'"
(click)="alignment.set('right')"
>
Right
</button>
</div>
<!-- Toggle button group -->
<div class="group" role="group" aria-label="Text styling">
<button ngToolbarWidget type="button" [attr.aria-pressed]="bold()" (click)="bold.set(!bold())">
Bold
</button>
<button
ngToolbarWidget
type="button"
[attr.aria-pressed]="italic()"
(click)="italic.set(!italic())"
>
Italic
</button>
</div>
Toolbars support two disabled modes:
By default, softDisabled is true, which allows disabled widgets to still receive focus. If you want to enable hard-disabled mode, set [softDisabled]="false" on the toolbar.
Toolbars automatically support right-to-left languages. Wrap the toolbar in a container with dir="rtl" to reverse the layout and keyboard navigation direction. Arrow key navigation adjusts automatically: left arrow moves to the next widget, right arrow to the previous.
Angular Aria provides component harnesses for testing toolbar components. Here is an example of how to use the harnesses in a component test:
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
import {ToolbarHarness} from '@angular/aria/toolbar/testing';
import {MyToolbarComponent} from './my-toolbar'; // Your component
describe('MyToolbarComponent', () => {
let fixture: ComponentFixture<MyToolbarComponent>;
let loader: HarnessLoader;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [MyToolbarComponent],
});
fixture = TestBed.createComponent(MyToolbarComponent);
await fixture.whenStable();
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should have widgets and update toggle state on click', async () => {
// Load the toolbar harness
const toolbar = await loader.getHarness(ToolbarHarness);
// Get all widgets
const widgets = await toolbar.getWidgets();
expect(widgets.length).toBe(3);
// Click the first widget
await widgets[0].click();
// Verify pressed state updated via click handler
expect(await widgets[0].isSelected()).toBe(true);
});
});
For detailed API documentation, inspect the following API references: