Skip to content

Commit

Permalink
docs(material/checkbox): Update checkbox docs & examples (#29234)
Browse files Browse the repository at this point in the history
(cherry picked from commit d783233)
  • Loading branch information
mmalerba committed Jun 12, 2024
1 parent 49eddf5 commit dd05235
Show file tree
Hide file tree
Showing 11 changed files with 93 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,12 @@ <h2 class="example-h2">Result</h2>

<section class="example-section">
<mat-checkbox
class="example-margin"
[(ngModel)]="checked"
[(indeterminate)]="indeterminate"
[labelPosition]="labelPosition"
[disabled]="disabled">
class="example-margin"
[(ngModel)]="checked"
[(indeterminate)]="indeterminate"
[labelPosition]="labelPosition()"
[disabled]="disabled()"
>
I'm a checkbox
</mat-checkbox>
</section>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {Component} from '@angular/core';
import {MatRadioModule} from '@angular/material/radio';
import {ChangeDetectionStrategy, Component, model} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatCardModule} from '@angular/material/card';
import {MatCheckboxModule} from '@angular/material/checkbox';
import {MatRadioModule} from '@angular/material/radio';

/**
* @title Configurable checkbox
Expand All @@ -13,10 +13,11 @@ import {MatCardModule} from '@angular/material/card';
styleUrl: 'checkbox-configurable-example.css',
standalone: true,
imports: [MatCardModule, MatCheckboxModule, FormsModule, MatRadioModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CheckboxConfigurableExample {
checked = false;
indeterminate = false;
labelPosition: 'before' | 'after' = 'after';
disabled = false;
readonly checked = model(false);
readonly indeterminate = model(false);
readonly labelPosition = model<'before' | 'after'>('after');
readonly disabled = model(false);
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
<mat-checkbox
required
[checked]="true"
name="first-name"
value="first-value"
aria-label="First checkbox">
required
[checked]="true"
name="first-name"
value="first-value"
aria-label="First checkbox"
>
First
</mat-checkbox>
<mat-checkbox indeterminate="true" [disabled]="disabled" aria-label="Second checkbox">
<mat-checkbox indeterminate="true" [disabled]="disabled()" aria-label="Second checkbox">
Second
</mat-checkbox>
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ describe('CheckboxHarnessExample', () => {
});

it('should toggle checkbox', async () => {
fixture.componentInstance.disabled = false;
fixture.componentRef.setInput('disabled', false);
fixture.changeDetectorRef.markForCheck();
const [checkedCheckbox, uncheckedCheckbox] = await loader.getAllHarnesses(MatCheckboxHarness);
await checkedCheckbox.toggle();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component} from '@angular/core';
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
import {MatCheckboxModule} from '@angular/material/checkbox';

/**
Expand All @@ -9,7 +9,8 @@ import {MatCheckboxModule} from '@angular/material/checkbox';
templateUrl: 'checkbox-harness-example.html',
standalone: true,
imports: [MatCheckboxModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CheckboxHarnessExample {
disabled = true;
readonly disabled = input(true);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,20 @@

<section class="example-section">
<span class="example-list-section">
<mat-checkbox class="example-margin"
[checked]="allComplete"
[color]="task.color"
[indeterminate]="someComplete()"
(change)="setAll($event.checked)">
{{task.name}}
<mat-checkbox
class="example-margin"
[checked]="task().completed"
[indeterminate]="partiallyComplete()"
(change)="update($event.checked)"
>
{{task().name}}
</mat-checkbox>
</span>
<span class="example-list-section">
<ul>
@for (subtask of task.subtasks; track subtask) {
@for (subtask of task().subtasks; track subtask; let i = $index) {
<li>
<mat-checkbox [(ngModel)]="subtask.completed"
[color]="subtask.color"
(ngModelChange)="updateAllComplete()">
<mat-checkbox [checked]="subtask.completed" (change)="update($event.checked, i)">
{{subtask.name}}
</mat-checkbox>
</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import {Component} from '@angular/core';
import {ThemePalette} from '@angular/material/core';
import {ChangeDetectionStrategy, Component, computed, signal} from '@angular/core';
import {FormsModule} from '@angular/forms';
import {MatCheckboxModule} from '@angular/material/checkbox';

export interface Task {
name: string;
completed: boolean;
color: ThemePalette;
subtasks?: Task[];
}

Expand All @@ -19,37 +17,37 @@ export interface Task {
styleUrl: 'checkbox-overview-example.css',
standalone: true,
imports: [MatCheckboxModule, FormsModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CheckboxOverviewExample {
task: Task = {
name: 'Indeterminate',
readonly task = signal<Task>({
name: 'Parent task',
completed: false,
color: 'primary',
subtasks: [
{name: 'Primary', completed: false, color: 'primary'},
{name: 'Accent', completed: false, color: 'accent'},
{name: 'Warn', completed: false, color: 'warn'},
{name: 'Child task 1', completed: false},
{name: 'Child task 2', completed: false},
{name: 'Child task 3', completed: false},
],
};
});

allComplete: boolean = false;

updateAllComplete() {
this.allComplete = this.task.subtasks != null && this.task.subtasks.every(t => t.completed);
}

someComplete(): boolean {
if (this.task.subtasks == null) {
readonly partiallyComplete = computed(() => {
const task = this.task();
if (!task.subtasks) {
return false;
}
return this.task.subtasks.filter(t => t.completed).length > 0 && !this.allComplete;
}
return task.subtasks.some(t => t.completed) && !task.subtasks.every(t => t.completed);
});

setAll(completed: boolean) {
this.allComplete = completed;
if (this.task.subtasks == null) {
return;
}
this.task.subtasks.forEach(t => (t.completed = completed));
update(completed: boolean, index?: number) {
this.task.update(task => {
if (index === undefined) {
task.completed = completed;
task.subtasks?.forEach(t => (t.completed = completed));
} else {
task.subtasks![index].completed = completed;
task.completed = task.subtasks?.every(t => t.completed) ?? true;
}
return {...task};
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {Component} from '@angular/core';
import {FormBuilder, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {JsonPipe} from '@angular/common';
import {ChangeDetectionStrategy, Component, inject} from '@angular/core';
import {FormBuilder, FormsModule, ReactiveFormsModule} from '@angular/forms';
import {MatCheckboxModule} from '@angular/material/checkbox';

/** @title Checkboxes with reactive forms */
Expand All @@ -10,13 +10,14 @@ import {MatCheckboxModule} from '@angular/material/checkbox';
styleUrl: 'checkbox-reactive-forms-example.css',
standalone: true,
imports: [FormsModule, ReactiveFormsModule, MatCheckboxModule, JsonPipe],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CheckboxReactiveFormsExample {
toppings = this._formBuilder.group({
private readonly _formBuilder = inject(FormBuilder);

readonly toppings = this._formBuilder.group({
pepperoni: false,
extracheese: false,
mushroom: false,
});

constructor(private _formBuilder: FormBuilder) {}
}
6 changes: 5 additions & 1 deletion src/material/checkbox/checkbox-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@ import {ThemePalette} from '@angular/material/core';

/** Default `mat-checkbox` options that can be overridden. */
export interface MatCheckboxDefaultOptions {
/** Default theme color palette to be used for checkboxes. */
/**
* Default theme color palette to be used for checkboxes. This API is supported in M2 themes
* only, it has no effect in M3 themes. For information on applying color variants in M3, see
* https://material.angular.io/guide/theming#using-component-color-variants
*/
color?: ThemePalette;
/** Default checkbox click action for checkboxes. */
clickAction?: MatCheckboxClickAction;
Expand Down
15 changes: 13 additions & 2 deletions src/material/checkbox/checkbox.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ enhanced with Material Design styling and animations.
<!-- example(checkbox-overview) -->

### Checkbox label

The checkbox label is provided as the content to the `<mat-checkbox>` element. The label can be
positioned before or after the checkbox by setting the `labelPosition` property to `'before'` or
`'after'`.
Expand All @@ -14,16 +15,19 @@ If you don't want the label to appear next to the checkbox, you can use
specify an appropriate label.

### Use with `@angular/forms`

`<mat-checkbox>` is compatible with `@angular/forms` and supports both `FormsModule`
and `ReactiveFormsModule`.

### Indeterminate state

`<mat-checkbox>` supports an `indeterminate` state, similar to the native `<input type="checkbox">`.
While the `indeterminate` property of the checkbox is true, it will render as indeterminate
regardless of the `checked` value. Any interaction with the checkbox by a user (i.e., clicking) will
remove the indeterminate state.

### Click action config

When user clicks on the `mat-checkbox`, the default behavior is toggle `checked` value and set
`indeterminate` to `false`. This behavior can be customized by
[providing a new value](https://angular.io/guide/dependency-injection)
Expand All @@ -38,22 +42,29 @@ providers: [
The possible values are:

#### `noop`

Do not change the `checked` value or `indeterminate` value. Developers have the power to
implement customized click actions.

#### `check`

Toggle `checked` value of the checkbox, ignore `indeterminate` value. If the
checkbox is in `indeterminate` state, the checkbox will display as an `indeterminate` checkbox
regardless the `checked` value.

#### `check-indeterminate`

Default behavior of `mat-checkbox`. Always set `indeterminate` to `false`
when user click on the `mat-checkbox`.
This matches the behavior of native `<input type="checkbox">`.

### Theming
The color of a `<mat-checkbox>` can be changed by using the `color` property. By default, checkboxes
use the theme's accent color. This can be changed to `'primary'` or `'warn'`.

The color of a `<mat-checkbox>` can be changed by specifying a `$color-variant` when applying the
`mat.checkbox-theme` or `mat.checkbox-color` mixins (see the
[theming guide](/guide/theming#using-component-color-variants) to learn more.) By default,
checkboxes use the theme's primary palette. This can be changed to `'secondary'`, `'tertiary'`,
or `'error'`.

### Accessibility

Expand Down
18 changes: 11 additions & 7 deletions src/material/checkbox/checkbox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,28 @@
* found in the LICENSE file at https://angular.io/license
*/

import {FocusableOption} from '@angular/cdk/a11y';
import {
ANIMATION_MODULE_TYPE,
AfterViewInit,
Attribute,
booleanAttribute,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
ElementRef,
EventEmitter,
forwardRef,
Inject,
Input,
NgZone,
numberAttribute,
OnChanges,
Optional,
Output,
SimpleChanges,
ViewChild,
ViewEncapsulation,
ANIMATION_MODULE_TYPE,
booleanAttribute,
forwardRef,
numberAttribute,
} from '@angular/core';
import {
AbstractControl,
Expand All @@ -36,8 +37,7 @@ import {
ValidationErrors,
Validator,
} from '@angular/forms';
import {_MatInternalFormField, MatRipple} from '@angular/material/core';
import {FocusableOption} from '@angular/cdk/a11y';
import {MatRipple, _MatInternalFormField} from '@angular/material/core';
import {
MAT_CHECKBOX_DEFAULT_OPTIONS,
MAT_CHECKBOX_DEFAULT_OPTIONS_FACTORY,
Expand Down Expand Up @@ -202,7 +202,11 @@ export class MatCheckbox

// TODO(crisbeto): this should be a ThemePalette, but some internal apps were abusing
// the lack of type checking previously and assigning random strings.
/** Palette color of the checkbox. */
/**
* Palette color of the checkbox. This API is supported in M2 themes only, it has no effect in M3
* themes. For information on applying color variants in M3, see
* https://material.angular.io/guide/theming#using-component-color-variants
*/
@Input() color: string | undefined;

/**
Expand Down

0 comments on commit dd05235

Please sign in to comment.