### Load all button harnesses and first button harness
Source: https://v21.material.angular.dev/guide/using-component-harnesses
Uses `getAllHarnesses` to get all MatButtonHarness instances (length 3) and `getHarness` to get the first one. All harness APIs are asynchronous and return Promises, so `async`/`await` is used.
```typescript
import {MatButtonHarness} from '@angular/material/button/testing';
...
it('should work', async () => {
const buttons = await loader.getAllHarnesses(MatButtonHarness); // length: 3
const firstButton = await loader.getHarness(MatButtonHarness); // === buttons[0]
});
```
--------------------------------
### Flat tree structure example
Source: https://v21.material.angular.dev/components/tree
Shows the DOM structure of a flat tree where nodes are rendered as siblings. Use this when you need a simpler structure for styling or virtual scrolling.
```html
parent node -- child node1 -- child node2
```
--------------------------------
### Example test using MyButtonComponentHarness
Source: https://v21.material.angular.dev/cdk/testing
Shows a unit test that uses a harness to load a button component and verify its text. The harness is obtained via `loader.getHarness` and the test asserts the button's text equals 'Confirm'.
```typescript
// Example of test with a harness for a component called MyButtonComponent
it('should load button with exact text', async () => {
const button = await loader.getHarness(MyButtonComponentHarness);
expect(await button.getText()).toBe('Confirm');
});
```
--------------------------------
### LiveAnnouncer example: inject and announce message
Source: https://v21.material.angular.dev/cdk/a11y
Inject `LiveAnnouncer` using Angular's `inject` function and call the `announce` method to communicate a message to screen-reader users.
```typescript
@Component({...})
export class MyComponent {
private liveAnnouncer = inject(LiveAnnouncer);
announceMessage() {
this.liveAnnouncer.announce("Hey Google");
}
}
```
--------------------------------
### Nested tree structure example
Source: https://v21.material.angular.dev/components/tree
Shows the DOM structure of a nested tree where children are placed inside their parent node. Use this when hierarchical relationships need visual representation.
```html
parent node
-- child node1 -- child node2
```
--------------------------------
### Focus region with cdkFocusRegionStart, cdkFocusInitial, cdkFocusRegionEnd
Source: https://v21.material.angular.dev/cdk/a11y
Example of declaring explicit focus regions using cdkFocusRegionStart, cdkFocusRegionEnd, and cdkFocusInitial. cdkFocusInitial specifies the initially focused element. Note that cdkFocusInitial requires cdkTrapFocusAutoCapture to work with CdkTrapFocus.
```html
Focus region startLinkInitially focusedFocus region end
```
--------------------------------
### Conditional tree node templates with when predicate
Source: https://v21.material.angular.dev/components/tree
The tree can include multiple node templates, selected by the when predicate of the matTreeNodeDef. This example shows a default template and a special template for nodes matching isSpecial.
```html
{{node.value}}
[ A special node {{node.value}} ]
```
--------------------------------
### Load harness for button inside a child loader
Source: https://v21.material.angular.dev/guide/using-component-harnesses
Uses `getChildLoader` to scope the loader to a `.footer` div, then gets the MatButtonHarness within that sub-section. This avoids brittle tests that depend on button order.
```typescript
it('should work', async () => {
const footerLoader = await loader.getChildLoader('.footer');
const footerButton = await footerLoader.getHarness(MatButtonHarness);
});
```
--------------------------------
### Filter harnesses with MatButtonHarness.with
Source: https://v21.material.angular.dev/guide/using-component-harnesses
Uses the static `with` method to create HarnessPredicate filters. Supports standard options `selector` and `ancestor`, plus `text` for MatButtonHarness. Examples filter by id, text, and a combination of class and regex text.
```typescript
it('should work', async () => {
// Harness for mat-button whose id is 'more-info'.
const info = await loader.getHarness(MatButtonHarness.with({selector: '#more-info'}));
// Harness for mat-button whose text is 'Cancel'.
const cancel = await loader.getHarness(MatButtonHarness.with({text: 'Cancel'}));
// Harness for mat-button with class 'confirm' and whose text is either 'Ok' or 'Okay'.
const okButton = await loader.getHarness(
MatButtonHarness.with({selector: '.confirm', text: /^(Ok|Okay)$/}));
});
```
--------------------------------
### cdkTrapFocus directive example
Source: https://v21.material.angular.dev/cdk/a11y
Example of using the cdkTrapFocus directive to trap Tab key focus within an element. Note that it does not prevent focus from moving out due to mouse interaction.
```html
```
--------------------------------
### Define high contrast styles with high-contrast mixin
Source: https://v21.material.angular.dev/cdk/a11y
Use the high-contrast mixin to define styles that only apply in high contrast mode. The mixin targets the forced-colors media query, and this example adds an outline to buttons in high contrast mode.
```scss
@use '@angular/cdk';
button {
@include cdk.high-contrast {
outline: solid 1px;
}
}
```
--------------------------------
### Customize tree with tree-overrides mixin
Source: https://v21.material.angular.dev/components/tree/styling
Use the `tree-overrides` mixin to customize tree styles. The example applies styles to the entire app by using the `:root` selector; change it to a specific selector to scope the styles. The mixin accepts a map of tokens such as `container-background-color` and `node-text-color`.
```scss
@use '@angular/material' as mat;
// Customize the entire app. Change :root to your selector if you want to scope the styles.
:root {
@include mat.tree-overrides((
container-background-color: orange,
node-text-color: red,
));
}
```
--------------------------------
### Use cdk-visually-hidden class on a checkbox
Source: https://v21.material.angular.dev/cdk/a11y
Apply the .cdk-visually-hidden class to an input element to visually hide it while keeping it accessible to screen readers. This example shows a custom checkbox wrapper with a visually hidden native checkbox.
```html
```
--------------------------------
### FocusKeyManager with withWrap
Source: https://v21.material.angular.dev/cdk/a11y
Shows how to enable wrapping navigation in a FocusKeyManager by calling the withWrap method.
```typescript
this.keyManager = new FocusKeyManager(...).withWrap();
```
--------------------------------
### mat-tree-node activation event
Source: https://v21.material.angular.dev/components/tree
For trees with nodes that have actions upon activation or click, mat-tree-node emits (activation) events when the user activates a node via keyboard. $event contains the node's data and is equivalent to the implicit data passed in the matTreeNodeDef context.
```html
```
--------------------------------
### Tree node with expand/collapse toggle
Source: https://v21.material.angular.dev/components/tree
Adds a matTreeNodeToggle button to expand/collapse the node. Setting [matTreeNodeToggleRecursive] to true expands/collapses recursively. Ensure aria-label is provided for icon buttons.
```html
{{node.value}}
```
--------------------------------
### Highlightable interface
Source: https://v21.material.angular.dev/cdk/a11y
Interface that items managed by an ActiveDescendantKeyManager must implement. Extends ListKeyManagerOption and requires setActiveStyles and setInactiveStyles methods.
```typescript
interface Highlightable extends ListKeyManagerOption {
setActiveStyles(): void;
setInactiveStyles(): void;
}
```
--------------------------------
### Create HarnessLoader in unit test
Source: https://v21.material.angular.dev/guide/using-component-harnesses
Imports HarnessLoader and TestbedHarnessEnvironment, then creates a loader in the fixture. This is used to locate Angular Material components in the component under test.
```typescript
import {HarnessLoader} from '@angular/cdk/testing';
import {TestbedHarnessEnvironment} from '@angular/cdk/testing/testbed';
let loader: HarnessLoader;
describe('my-component', () => {
beforeEach(async () => {
TestBed.configureTestingModule({imports: [MyModule], declarations: [UserProfile]});
fixture = TestBed.createComponent(UserProfile);
loader = TestbedHarnessEnvironment.loader(fixture);
});
}
```
--------------------------------
### Test using MatButtonHarness to click a button
Source: https://v21.material.angular.dev/guide/using-component-harnesses
This test uses MatButtonHarness to find a button with selector '.confirm', checks it is not disabled, clicks it, and verifies the component's 'confirmed' property becomes true. The harness automatically invokes change detection and waits for the fixture to be stable, so no explicit 'fixture.detectChanges()' call is needed.
```typescript
it('should mark confirmed when ok button clicked', async () => {
const okButton = await loader.getHarness(MatButtonHarness.with({selector: '.confirm'});
expect(fixture.componentInstance.confirmed).toBe(false);
expect(await okButton.isDisabled()).toBe(false);
await okButton.click();
expect(fixture.componentInstance.confirmed).toBe(true);
});
```
--------------------------------
### ListKeyManager
Source: https://v21.material.angular.dev/cdk/a11y/overview
Manages the active option in a list of items based on keyboard interaction. Intended for components with role="menu" or role="listbox" patterns.
```APIDOC
## ListKeyManager
### Description
Manages the active option in a list of items based on keyboard interaction. Intended to be used with components that correspond to a `role="menu"` or `role="listbox"` pattern.
### Basic Usage
Any component that uses a `ListKeyManager` will generally do three things:
- Create a `@ViewChildren` query for the options being managed.
- Initialize the `ListKeyManager`, passing in the options.
- Forward keyboard events from the managed component to the `ListKeyManager`.
Each option should implement the `ListKeyManagerOption` interface:
```
interface ListKeyManagerOption {
disabled?: boolean;
getLabel?(): string;
}
```
### Wrapping
Navigation through options can be made to wrap via the `withWrap` method:
```
this.keyManager = new FocusKeyManager(...).withWrap();
```
### Types of List Key Managers
There are two varieties of `ListKeyManager`: `FocusKeyManager` and `ActiveDescendantKeyManager`.
#### FocusKeyManager
Used when options will directly receive browser focus. Each item managed must implement the `FocusableOption` interface:
```
interface FocusableOption extends ListKeyManagerOption {
focus(): void;
}
```
#### ActiveDescendantKeyManager
Used when options will be marked as active via `aria-activedescendant`. Each item managed must implement the `Highlightable` interface:
```
interface Highlightable extends ListKeyManagerOption {
setActiveStyles(): void;
setInactiveStyles(): void;
}
```
Each item must also have an ID bound to the listbox's or menu's `aria-activedescendant`.
```
--------------------------------
### Basic tree node definition with matTreeNodeDef
Source: https://v21.material.angular.dev/components/tree
Defines a tree node template using *matTreeNodeDef. The directive exports the node data for bindings in the template.
```html
{{node.key}}: {{node.value}}
```
--------------------------------
### Test with Angular Material component harnesses
Source: https://v21.material.angular.dev/guide/using-component-harnesses
Same test using MatSelectHarness and HarnessLoader. It uses the harness API to open the select and select an option by text, eliminating manual detectChanges and whenStable calls.
```typescript
describe('issue-report-selector', () => {
let fixture: ComponentFixture;
let loader: HarnessLoader;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [IssueReportSelectorModule],
declarations: [IssueReportSelector],
});
fixture = TestBed.createComponent(IssueReportSelector);
fixture.detectChanges();
loader = TestbedHarnessEnvironment.loader(fixture);
});
it('should switch to bug report template', async () => {
expect(fixture.debugElement.query('bug-report-form')).toBeNull();
const select = await loader.getHarness(MatSelectHarness);
await select.open();
const bugOption = await select.getOption({text: 'Bug'});
await bugOption.click();
expect(fixture.debugElement.query('bug-report-form')).not.toBeNull();
});
});
```
--------------------------------
### Test without component harnesses
Source: https://v21.material.angular.dev/guide/using-component-harnesses
Traditional test using fixture.debugElement and CSS selectors to interact with the component. It requires manual detectChanges and whenStable calls and relies on internal DOM structure like .mat-select-trigger.
```typescript
describe('issue-report-selector', () => {
let fixture: ComponentFixture;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [IssueReportSelectorModule],
declarations: [IssueReportSelector],
});
fixture = TestBed.createComponent(IssueReportSelector);
fixture.detectChanges();
});
it('should switch to bug report template', async () => {
expect(fixture.debugElement.query('bug-report-form')).toBeNull();
const selectTrigger = fixture.debugElement.query(By.css('.mat-select-trigger'));
selectTrigger.triggerEventHandler('click', {});
fixture.detectChanges();
await fixture.whenStable();
const options = document.querySelectorAll('.mat-select-panel mat-option');
options[1].click(); // Click the second option, "Bug".
fixture.detectChanges();
await fixture.whenStable();
expect(fixture.debugElement.query('bug-report-form')).not.toBeNull();
});
});
```
--------------------------------
### Toolbar with title and actions
Source: https://v21.material.angular.dev/components/toolbar
A common pattern: place a title on the left and actions on the right using flexbox. The toolbar itself does not position content.
```html
My App
```
--------------------------------
### Toolbar with multiple rows
Source: https://v21.material.angular.dev/components/toolbar
Place `` elements inside a `` to create multiple rows. Placing content outside a `` when multiple rows are specified is not supported.
```html
Custom ToolbarSecond Rowfavoritedelete
```
--------------------------------
### ListKeyManagerOption interface
Source: https://v21.material.angular.dev/cdk/a11y
Defines the interface that each option managed by a ListKeyManager must implement. It includes an optional disabled property and an optional getLabel method.
```typescript
interface ListKeyManagerOption {
disabled?: boolean;
getLabel?(): string;
}
```
--------------------------------
### Positioning toolbar content with flex
Source: https://v21.material.angular.dev/components/toolbar
Use `display: flex` to position toolbar content, such as a title on the left and actions on the right. The toolbar does not perform any positioning itself.
```css
.example-toolbar {
display: flex;
align-items: center;
justify-content: space-between;
}
```
--------------------------------
### Nested tree node template with matTreeNodeOutlet
Source: https://v21.material.angular.dev/components/tree
For nested trees, the node template must include a matTreeNodeOutlet to mark where children will be rendered.
```html
{{node.value}}
```
--------------------------------
### matTreeNodePadding in flat tree node template
Source: https://v21.material.angular.dev/components/tree
Use matTreeNodePadding on a mat-tree-node in a flat tree to display the level information of a flat tree node. This is unnecessary for nested trees because DOM hierarchy provides padding via CSS.
```html
{{node.value}}
```
--------------------------------
### FocusableOption interface
Source: https://v21.material.angular.dev/cdk/a11y
Interface that items managed by a FocusKeyManager must implement. Extends ListKeyManagerOption and requires a focus method.
```typescript
interface FocusableOption extends ListKeyManagerOption {
focus(): void;
}
```
--------------------------------
### InteractivityChecker
Source: https://v21.material.angular.dev/cdk/a11y/overview
Used to check the interactivity of an element, capturing disabled, visible, tabbable, and focusable states for accessibility purposes.
```APIDOC
## InteractivityChecker
### Description
`InteractivityChecker` is used to check the interactivity of an element, capturing disabled, visible, tabbable, and focusable states for accessibility purposes. See the API docs for more details.
```
--------------------------------
### TreeKeyManager
Source: https://v21.material.angular.dev/cdk/a11y/overview
Manages the active option in a tree view. Use for components that implement a role="tree" pattern.
```APIDOC
## TreeKeyManager
### Description
Manages the active option in a tree view. Use this key manager for components that implement a `role="tree"` pattern.
### Basic Usage
Any component that uses a `TreeKeyManager` should do three things:
- Create a `@ViewChildren` query for the tree items being managed.
- Initialize the `TreeKeyManager`, passing in the options.
- Forward keyboard events from the managed component to the `TreeKeyManager` via `onKeydown`.
Each tree item should implement the `TreeKeyManagerItem` interface.
### Focus Management
The `TreeKeyManager` will handle focusing the appropriate item on keyboard interactions.
`tabindex` should also be set by the component when the active item changes. This can be listened to via the `change` property on the `TreeKeyManager`. In particular, the tree should only have a `tabindex` set if there is no active item, and should not have a `tabindex` set if there is an active item. Only the HTML node corresponding to the active item should have a `tabindex` set to `0`, with all other items set to `-1`.
```
--------------------------------
### mat-tree with trackBy for performance
Source: https://v21.material.angular.dev/components/tree
Provide a trackBy function to the tree to uniquely identify nodes, similar to Angular's ngFor trackBy, to improve performance when data changes.
```html
```
--------------------------------
### cdkTrapFocus
Source: https://v21.material.angular.dev/cdk/a11y/overview
Directive that traps Tab key focus within an element. Intended for accessible experiences like modal dialogs.
```APIDOC
## cdkTrapFocus
### Description
The `cdkTrapFocus` directive traps `Tab` key focus within an element. This is intended to be used to create accessible experience for components like modal dialogs, where focus must be constrained.
Import `CdkTrapFocus` in your component to use this directive.
### Usage Example
```