Toolbar
Обзор
Контейнер для группировки связанных контролов и действий с клавиатурной навигацией — обычно используется для форматирования текста, toolbars и командных панелей.
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: var(--septenary-contrast);
}
.group {
gap: 0.5rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 4px;
font-size: 1.25rem;
background-color: transparent;
color: var(--primary-contrast);
}
[ngToolbarWidget]:hover {
background-color: color-mix(in srgb, var(--primary-contrast) 10%, transparent);
}
[ngToolbarWidget]:active {
background-color: color-mix(in srgb, var(--primary-contrast) 15%, transparent);
}
[ngToolbarWidget]:focus {
outline-offset: -1px;
outline: 1px solid color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
[ngToolbarWidget][aria-pressed="true"],
[ngToolbarWidget][aria-checked="true"] {
color: color-mix(in srgb, var(--hot-pink) 80%, var(--primary-contrast));
background-color: color-mix(in srgb, var(--hot-pink) 10%, transparent);
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar class="material-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
display: flex;
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
width: 3rem;
height: 3rem;
font-size: 1.25rem;
border-radius: 2rem;
color: color-mix(in srgb, var(--vivid-pink) 70%, var(--full-contrast));
background-color: color-mix(in srgb, var(--vivid-pink) 20%, transparent);
transition:
width 0.2s ease-in-out,
background-color 0.15s ease-in-out,
color 0.15s ease-in-out;
}
[ngToolbarWidget]:focus {
outline-offset: 2px;
outline: 2px solid var(--vivid-pink);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
background-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--full-contrast));
color: var(--page-background);
}
[ngToolbarWidget][aria-checked='true'] {
width: 4.5rem;
}
.group {
display: flex;
gap: 0.5rem;
}
.separator {
width: 1px;
margin: 0 1rem;
height: calc(100% - 2rem);
background-color: var(--quinary-contrast);
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar class="retro-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--page-background));
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 1rem;
}
.group {
gap: 1rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
padding: 0.5rem;
font-size: 1.25rem;
color: var(--page-background);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
[ngToolbarWidget]:focus,
[ngToolbarWidget]:hover {
transform: translate(1px, 1px);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
transform: translate(4px, 4px);
box-shadow: var(--retro-pressed-shadow);
background-color: color-mix(in srgb, var(--retro-button-color) 60%, var(--gray-50));
}
[ngToolbarWidget]:focus {
outline-offset: 4px;
outline: 4px dashed var(--retro-button-color);
}
Использование
Toolbar лучше всего подходит для группировки связанных контролов, к которым пользователи часто обращаются. Рассмотрите toolbar, когда:
- Несколько связанных действий — несколько контролов выполняют связанные функции (например, кнопки форматирования текста)
- Важна эффективность клавиатуры — пользователи выигрывают от быстрой навигации стрелками
- Сгруппированные контролы — нужно организовать контролы в логические секции с разделителями
- Частый доступ — контролы используются многократно в рамках workflow
Избегайте toolbar, когда:
- Достаточно простой группы кнопок — для 2–3 несвязанных действий лучше отдельные кнопки
- Контролы не связаны — toolbar подразумевает логическую группировку; несвязанные контролы путают пользователей
- Сложная вложенная навигация — глубокие иерархии лучше обслуживаются menus или navigation-компонентами
Возможности
Toolbar Angular предоставляет полностью доступную реализацию toolbar с:
- Клавиатурной навигацией — перемещение по widgets стрелками, активация Enter или Space
- Поддержкой screen reader — встроенные ARIA-атрибуты для вспомогательных технологий
- Группами widgets — организация связанных widgets вроде radio button groups или toggle button groups
- Гибкой ориентацией — горизонтальные или вертикальные layout с автоматической клавиатурной навигацией
- Signal-based реактивностью — реактивное управление состоянием через сигналы Angular
- Поддержкой двунаправленного текста — автоматическая обработка языков справа налево (RTL)
- Настраиваемым фокусом — выбор между wrapping-навигацией или жёсткими остановками на краях
Примеры
Базовый горизонтальный toolbar
Горизонтальные toolbars организуют контролы слева направо — распространённый паттерн в текстовых редакторах и design tools. Стрелки перемещают между widgets, удерживая фокус внутри toolbar, пока пользователи не нажмут Tab для перехода к следующему элементу страницы.
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: var(--septenary-contrast);
}
.group {
gap: 0.5rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 4px;
font-size: 1.25rem;
background-color: transparent;
color: var(--primary-contrast);
}
[ngToolbarWidget]:hover {
background-color: color-mix(in srgb, var(--primary-contrast) 10%, transparent);
}
[ngToolbarWidget]:active {
background-color: color-mix(in srgb, var(--primary-contrast) 15%, transparent);
}
[ngToolbarWidget]:focus {
outline-offset: -1px;
outline: 1px solid color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
[ngToolbarWidget][aria-pressed="true"],
[ngToolbarWidget][aria-checked="true"] {
color: color-mix(in srgb, var(--hot-pink) 80%, var(--primary-contrast));
background-color: color-mix(in srgb, var(--hot-pink) 10%, transparent);
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar class="material-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
display: flex;
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
width: 3rem;
height: 3rem;
font-size: 1.25rem;
border-radius: 2rem;
color: color-mix(in srgb, var(--vivid-pink) 70%, var(--full-contrast));
background-color: color-mix(in srgb, var(--vivid-pink) 20%, transparent);
transition:
width 0.2s ease-in-out,
background-color 0.15s ease-in-out,
color 0.15s ease-in-out;
}
[ngToolbarWidget]:focus {
outline-offset: 2px;
outline: 2px solid var(--vivid-pink);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
background-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--full-contrast));
color: var(--page-background);
}
[ngToolbarWidget][aria-checked='true'] {
width: 4.5rem;
}
.group {
display: flex;
gap: 0.5rem;
}
.separator {
width: 1px;
margin: 0 1rem;
height: calc(100% - 2rem);
background-color: var(--quinary-contrast);
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar class="retro-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--page-background));
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 1rem;
}
.group {
gap: 1rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
padding: 0.5rem;
font-size: 1.25rem;
color: var(--page-background);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
[ngToolbarWidget]:focus,
[ngToolbarWidget]:hover {
transform: translate(1px, 1px);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
transform: translate(4px, 4px);
box-shadow: var(--retro-pressed-shadow);
background-color: color-mix(in srgb, var(--retro-button-color) 60%, var(--gray-50));
}
[ngToolbarWidget]:focus {
outline-offset: 4px;
outline: 4px dashed var(--retro-button-color);
}
Вертикальный toolbar
Вертикальные toolbars складывают контролы сверху вниз — полезно для side panels или вертикальных command palettes. Стрелки вверх и вниз перемещают между widgets.
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget],
})
export class App {}
app.html
<div ngToolbar orientation="vertical" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: flex-start;
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
flex-direction: column;
padding: 1rem 0.5rem;
border-radius: 0.5rem;
background-color: var(--septenary-contrast);
}
.group {
gap: 0.5rem;
display: flex;
flex-direction: column;
}
.separator {
height: 1px;
align-self: center;
width: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 4px;
font-size: 1.25rem;
background-color: transparent;
color: var(--primary-contrast);
}
[ngToolbarWidget]:hover {
background-color: color-mix(in srgb, var(--primary-contrast) 10%, transparent);
}
[ngToolbarWidget]:active {
background-color: color-mix(in srgb, var(--primary-contrast) 15%, transparent);
}
[ngToolbarWidget]:focus {
outline-offset: -1px;
outline: 1px solid color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
[ngToolbarWidget][aria-pressed="true"],
[ngToolbarWidget][aria-checked="true"] {
color: color-mix(in srgb, var(--hot-pink) 80%, var(--primary-contrast));
background-color: color-mix(in srgb, var(--hot-pink) 10%, transparent);
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget],
})
export class App {}
app.html
<div
ngToolbar
orientation="vertical"
class="vertical-material-toolbar"
aria-label="Text Formatting Tools"
>
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: flex-start;
}
[ngToolbar] {
display: flex;
flex-direction: column;
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
width: 3rem;
height: 3rem;
font-size: 1.25rem;
border-radius: 2rem;
color: color-mix(in srgb, var(--vivid-pink) 70%, var(--full-contrast));
background-color: color-mix(in srgb, var(--vivid-pink) 20%, transparent);
transition:
height 0.2s ease-in-out,
background-color 0.15s ease-in-out,
color 0.15s ease-in-out;
}
[ngToolbarWidget]:focus {
outline-offset: 2px;
outline: 2px solid var(--vivid-pink);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
background-color: var(--vivid-pink);
color: var(--page-background);
}
[ngToolbarWidget][aria-checked='true'] {
height: 4.5rem;
}
.group {
gap: 0.5rem;
display: flex;
flex-direction: column;
}
.separator {
width: 1px;
margin: 1rem 0;
height: calc(100% - 2rem);
background-color: var(--quinary-contrast);
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget],
})
export class App {}
app.html
<div ngToolbar orientation="vertical" class="retro-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: flex-start;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--page-background));
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 1rem;
flex-direction: column;
}
.group {
gap: 1rem;
display: flex;
flex-direction: column;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
padding: 0.5rem;
font-size: 1.25rem;
color: var(--page-background);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
[ngToolbarWidget]:focus,
[ngToolbarWidget]:hover {
transform: translate(1px, 1px);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
transform: translate(4px, 4px);
box-shadow: var(--retro-pressed-shadow);
background-color: color-mix(in srgb, var(--retro-button-color) 60%, var(--gray-50));
}
[ngToolbarWidget]:focus {
outline-offset: 4px;
outline: 4px dashed var(--retro-button-color);
}
Группы widgets
Группы widgets содержат связанные контролы, работающие вместе — например, опции выравнивания текста или форматирования списков. Группы поддерживают собственное внутреннее состояние, участвуя в навигации toolbar.
В примерах выше кнопки выравнивания обёрнуты в ngToolbarWidgetGroup с role="radiogroup", чтобы создать группу взаимоисключающего выбора.
Input multi контролирует, могут ли несколько widgets в группе быть выбраны одновременно:
<!-- Single selection (radio group) -->
<div ngToolbarWidgetGroup role="radiogroup" aria-label="Alignment">
<button ngToolbarWidget value="left">Left</button>
<button ngToolbarWidget value="center">Center</button>
<button ngToolbarWidget value="right">Right</button>
</div>
<!-- Multiple selection (toggle group) -->
<div ngToolbarWidgetGroup [multi]="true" aria-label="Formatting">
<button ngToolbarWidget value="bold">Bold</button>
<button ngToolbarWidget value="italic">Italic</button>
<button ngToolbarWidget value="underline">Underline</button>
</div>
Отключённые widgets
Toolbars поддерживают два режима disabled:
- Soft-disabled widgets остаются focusable, но визуально показывают недоступность
- Hard-disabled widgets полностью исключены из клавиатурной навигации.
По умолчанию softDisabled равен true, что позволяет disabled widgets всё ещё получать фокус. Чтобы включить hard-disabled режим, задайте [softDisabled]="false" на toolbar.
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
disabled
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div
ngToolbarWidgetGroup
role="radiogroup"
class="group"
aria-label="Text alignment options"
disabled
>
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: var(--septenary-contrast);
}
.group {
gap: 0.5rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 4px;
font-size: 1.25rem;
background-color: transparent;
color: var(--primary-contrast);
}
[ngToolbarWidget]:hover {
background-color: color-mix(in srgb, var(--primary-contrast) 10%, transparent);
}
[ngToolbarWidget]:active {
background-color: color-mix(in srgb, var(--primary-contrast) 15%, transparent);
}
[ngToolbarWidget]:focus {
outline-offset: -1px;
outline: 1px solid color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
[ngToolbarWidget][aria-pressed="true"],
[ngToolbarWidget][aria-checked="true"] {
color: color-mix(in srgb, var(--hot-pink) 80%, var(--primary-contrast));
background-color: color-mix(in srgb, var(--hot-pink) 10%, transparent);
}
[ngToolbarWidget][aria-disabled="true"] {
cursor: default;
opacity: 0.45;
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar class="disabled-material-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
disabled
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div
ngToolbarWidgetGroup
role="radiogroup"
class="group"
aria-label="Text alignment options"
disabled
>
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
display: flex;
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
width: 3rem;
height: 3rem;
font-size: 1.25rem;
border-radius: 2rem;
color: color-mix(in srgb, var(--vivid-pink) 70%, var(--full-contrast));
background-color: color-mix(in srgb, var(--vivid-pink) 20%, transparent);
transition:
width 0.2s ease-in-out,
background-color 0.15s ease-in-out,
color 0.15s ease-in-out;
}
[ngToolbarWidget]:focus {
outline-offset: 2px;
outline: 2px solid var(--vivid-pink);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
background-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--full-contrast));
color: var(--page-background);
}
[ngToolbarWidget][aria-checked='true'] {
width: 4.5rem;
}
.group {
display: flex;
gap: 0.5rem;
}
.separator {
width: 1px;
margin: 0 1rem;
height: calc(100% - 2rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget][aria-disabled="true"] {
cursor: default;
opacity: 0.45;
}
app.ts
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar class="retro-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
disabled
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div
ngToolbarWidgetGroup
role="radiogroup"
class="group"
aria-label="Text alignment options"
disabled
>
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--page-background));
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 1rem;
}
.group {
gap: 1rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
padding: 0.5rem;
font-size: 1.25rem;
color: var(--page-background);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
[ngToolbarWidget]:focus,
[ngToolbarWidget]:hover {
transform: translate(1px, 1px);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
transform: translate(4px, 4px);
box-shadow: var(--retro-pressed-shadow);
background-color: color-mix(in srgb, var(--retro-button-color) 60%, var(--gray-50));
}
[ngToolbarWidget]:focus {
outline-offset: 4px;
outline: 4px dashed var(--retro-button-color);
}
[ngToolbarWidget][aria-disabled='true'] {
cursor: default;
opacity: 0.45;
}
Поддержка right-to-left (RTL)
Toolbars автоматически поддерживают языки справа налево. Оберните toolbar в контейнер с dir="rtl", чтобы обратить layout и направление клавиатурной навигации. Навигация стрелками корректируется автоматически: стрелка влево переходит к следующему widget, стрелка вправо — к предыдущему.
app.ts
import {Dir} from '@angular/cdk/bidi';
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Dir, Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar dir="rtl" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 0.5rem 1rem;
border-radius: 0.5rem;
background-color: var(--septenary-contrast);
}
.group {
gap: 0.5rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
cursor: pointer;
padding: 0.5rem;
border-radius: 4px;
font-size: 1.25rem;
background-color: transparent;
color: var(--primary-contrast);
}
[ngToolbarWidget]:hover {
background-color: color-mix(in srgb, var(--primary-contrast) 10%, transparent);
}
[ngToolbarWidget]:active {
background-color: color-mix(in srgb, var(--primary-contrast) 15%, transparent);
}
[ngToolbarWidget]:focus {
outline-offset: -1px;
outline: 1px solid color-mix(in srgb, var(--hot-pink) 60%, transparent);
}
[ngToolbarWidget][aria-pressed="true"],
[ngToolbarWidget][aria-checked="true"] {
color: color-mix(in srgb, var(--hot-pink) 80%, var(--primary-contrast));
background-color: color-mix(in srgb, var(--hot-pink) 10%, transparent);
}
app.ts
import {Dir} from '@angular/cdk/bidi';
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Dir, Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar dir="rtl" class="rtl-material-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
}
[ngToolbar] {
display: flex;
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
width: 3rem;
height: 3rem;
font-size: 1.25rem;
border-radius: 2rem;
color: color-mix(in srgb, var(--vivid-pink) 70%, var(--full-contrast));
background-color: color-mix(in srgb, var(--vivid-pink) 20%, transparent);
transition:
width 0.2s ease-in-out,
background-color 0.15s ease-in-out,
color 0.15s ease-in-out;
}
[ngToolbarWidget]:focus {
outline-offset: 2px;
outline: 2px solid var(--vivid-pink);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
background-color: var(--vivid-pink);
color: var(--page-background);
}
[ngToolbarWidget][aria-checked='true'] {
width: 4.5rem;
}
.group {
display: flex;
gap: 0.5rem;
}
.separator {
width: 1px;
margin: 0 1rem;
height: calc(100% - 2rem);
background-color: var(--quinary-contrast);
}
app.ts
import {Dir} from '@angular/cdk/bidi';
import {Component} from '@angular/core';
import {Toolbar, ToolbarWidget, ToolbarWidgetGroup} from '@angular/aria/toolbar';
@Component({
selector: 'app-root',
templateUrl: 'app.html',
styleUrl: 'app.css',
imports: [Dir, Toolbar, ToolbarWidget, ToolbarWidgetGroup],
})
export class App {}
app.html
<div ngToolbar dir="rtl" class="rtl-retro-toolbar" aria-label="Text Formatting Tools">
<div class="group">
<button
ngToolbarWidget
value="undo"
type="button"
aria-label="undo"
class="material-symbols-outlined"
translate="no"
>
undo
</button>
<button
ngToolbarWidget
value="redo"
type="button"
aria-label="redo"
class="material-symbols-outlined"
translate="no"
>
redo
</button>
</div>
<div class="separator" role="separator"></div>
<div class="group">
<button
ngToolbarWidget
value="bold"
type="button"
aria-label="bold"
#bold="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="bold.selected()"
translate="no"
>
format_bold
</button>
<button
ngToolbarWidget
value="italic"
type="button"
aria-label="italic"
#italic="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="italic.selected()"
translate="no"
>
format_italic
</button>
<button
ngToolbarWidget
value="underlined"
type="button"
aria-label="underlined"
#underlined="ngToolbarWidget"
class="material-symbols-outlined"
[aria-pressed]="underlined.selected()"
translate="no"
>
format_underlined
</button>
</div>
<div class="separator" role="separator"></div>
<div ngToolbarWidgetGroup role="radiogroup" class="group" aria-label="Text alignment options">
<button
ngToolbarWidget
role="radio"
type="button"
value="align left"
aria-label="align left"
#leftAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="leftAlign.selected()"
translate="no"
>
format_align_left
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align center"
aria-label="align center"
#centerAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="centerAlign.selected()"
translate="no"
>
format_align_center
</button>
<button
ngToolbarWidget
role="radio"
type="button"
value="align right"
aria-label="align right"
#rightAlign="ngToolbarWidget"
class="material-symbols-outlined"
[aria-checked]="rightAlign.selected()"
translate="no"
>
format_align_right
</button>
</div>
</div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');
:host {
display: flex;
justify-content: center;
font-family: 'Press Start 2P';
--retro-button-color: color-mix(in srgb, var(--vivid-pink) 80%, var(--page-background));
--retro-shadow-light: color-mix(in srgb, var(--retro-button-color) 90%, #fff);
--retro-shadow-dark: color-mix(in srgb, var(--retro-button-color) 90%, #000);
--retro-elevated-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast);
--retro-flat-shadow:
4px 0px 0px 0px var(--tertiary-contrast), 0px 4px 0px 0px var(--tertiary-contrast),
-4px 0px 0px 0px var(--tertiary-contrast), 0px -4px 0px 0px var(--tertiary-contrast);
--retro-clickable-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-light),
inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 8px 8px 0px 0px var(--tertiary-contrast);
--retro-pressed-shadow:
inset 4px 4px 0px 0px var(--retro-shadow-dark),
inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--tertiary-contrast),
0px 4px 0px 0px var(--tertiary-contrast), -4px 0px 0px 0px var(--tertiary-contrast),
0px -4px 0px 0px var(--tertiary-contrast), 0px 0px 0px 0px var(--tertiary-contrast);
}
[ngToolbar] {
gap: 1.5rem;
display: flex;
padding: 1rem;
}
.group {
gap: 1rem;
display: flex;
}
.separator {
width: 1px;
align-self: center;
height: calc(100% - 1rem);
background-color: var(--quinary-contrast);
}
[ngToolbarWidget] {
border: none;
outline: none;
cursor: pointer;
padding: 0.5rem;
font-size: 1.25rem;
color: var(--page-background);
background-color: var(--retro-button-color);
box-shadow: var(--retro-clickable-shadow);
transition:
transform 0.1s,
box-shadow 0.1s;
}
[ngToolbarWidget]:focus,
[ngToolbarWidget]:hover {
transform: translate(1px, 1px);
}
[ngToolbarWidget]:active,
[ngToolbarWidget][aria-pressed='true'],
[ngToolbarWidget][aria-checked='true'] {
transform: translate(4px, 4px);
box-shadow: var(--retro-pressed-shadow);
background-color: color-mix(in srgb, var(--retro-button-color) 60%, var(--gray-50));
}
[ngToolbarWidget]:focus {
outline-offset: 4px;
outline: 4px dashed var(--retro-button-color);
}
Тестирование
Angular Aria предоставляет component harnesses для тестирования компонентов toolbar. Пример использования harnesses в тесте компонента:
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 allow selection', 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 selection state
expect(await widgets[0].isSelected()).toBe(true);
});
});
API reference
Подробную API-документацию смотрите в следующих API reference: