Skip to content

Commit 73939a8

Browse files
authored
feat(material/slide-toggle): add full-width support (#33424)
Adds support for a `fullWidth` input on the slide toggle that'll make it stretch to fill its container. This is useful for mobile-focused UIs. Fixes #24754.
1 parent d829d1c commit 73939a8

11 files changed

Lines changed: 80 additions & 1 deletion

File tree

goldens/material/slide-toggle/index.api.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export class MatSlideToggle implements OnDestroy, AfterContentInit, OnChanges, C
4646
_focused: boolean;
4747
// (undocumented)
4848
protected _focusMonitor: FocusMonitor;
49+
fullWidth: boolean;
4950
// (undocumented)
5051
_getAriaLabelledBy(): string | null;
5152
_handleClick(): void;
@@ -64,6 +65,8 @@ export class MatSlideToggle implements OnDestroy, AfterContentInit, OnChanges, C
6465
// (undocumented)
6566
static ngAcceptInputType_disableRipple: unknown;
6667
// (undocumented)
68+
static ngAcceptInputType_fullWidth: unknown;
69+
// (undocumented)
6770
static ngAcceptInputType_hideIcon: unknown;
6871
// (undocumented)
6972
static ngAcceptInputType_required: unknown;
@@ -88,7 +91,7 @@ export class MatSlideToggle implements OnDestroy, AfterContentInit, OnChanges, C
8891
validate(control: AbstractControl<boolean>): ValidationErrors | null;
8992
writeValue(value: any): void;
9093
// (undocumented)
91-
static ɵcmp: i0.ɵɵComponentDeclaration<MatSlideToggle, "mat-slide-toggle", ["matSlideToggle"], { "name": { "alias": "name"; "required": false; }; "id": { "alias": "id"; "required": false; }; "labelPosition": { "alias": "labelPosition"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; }; "required": { "alias": "required"; "required": false; }; "color": { "alias": "color"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "disableRipple": { "alias": "disableRipple"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; }; "checked": { "alias": "checked"; "required": false; }; "hideIcon": { "alias": "hideIcon"; "required": false; }; "disabledInteractive": { "alias": "disabledInteractive"; "required": false; }; }, { "change": "change"; "toggleChange": "toggleChange"; }, never, ["*"], true, never>;
94+
static ɵcmp: i0.ɵɵComponentDeclaration<MatSlideToggle, "mat-slide-toggle", ["matSlideToggle"], { "name": { "alias": "name"; "required": false; }; "id": { "alias": "id"; "required": false; }; "labelPosition": { "alias": "labelPosition"; "required": false; }; "ariaLabel": { "alias": "aria-label"; "required": false; }; "ariaLabelledby": { "alias": "aria-labelledby"; "required": false; }; "ariaDescribedby": { "alias": "aria-describedby"; "required": false; }; "required": { "alias": "required"; "required": false; }; "color": { "alias": "color"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "fullWidth": { "alias": "fullWidth"; "required": false; }; "disableRipple": { "alias": "disableRipple"; "required": false; }; "tabIndex": { "alias": "tabIndex"; "required": false; }; "checked": { "alias": "checked"; "required": false; }; "hideIcon": { "alias": "hideIcon"; "required": false; }; "disabledInteractive": { "alias": "disabledInteractive"; "required": false; }; }, { "change": "change"; "toggleChange": "toggleChange"; }, never, ["*"], true, never>;
9295
// (undocumented)
9396
static ɵfac: i0.ɵɵFactoryDeclaration<MatSlideToggle, never>;
9497
}

src/components-examples/material/slide-toggle/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export {SlideToggleConfigurableExample} from './slide-toggle-configurable/slide-
22
export {SlideToggleFormsExample} from './slide-toggle-forms/slide-toggle-forms-example';
33
export {SlideToggleOverviewExample} from './slide-toggle-overview/slide-toggle-overview-example';
44
export {SlideToggleHarnessExample} from './slide-toggle-harness/slide-toggle-harness-example';
5+
export {SlideToggleFullWidthExample} from './slide-toggle-full-width/slide-toggle-full-width-example';
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.example-full-width-container {
2+
width: 300px;
3+
border: 1px solid #ccc;
4+
padding: 16px;
5+
border-radius: 4px;
6+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<div class="example-full-width-container">
2+
<mat-slide-toggle fullWidth labelPosition="before">Full width slide toggle</mat-slide-toggle>
3+
<mat-slide-toggle fullWidth>Full width slide toggle</mat-slide-toggle>
4+
</div>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import {Component} from '@angular/core';
2+
import {MatSlideToggle} from '@angular/material/slide-toggle';
3+
4+
/**
5+
* @title Full-width slide toggle
6+
*/
7+
@Component({
8+
selector: 'slide-toggle-full-width-example',
9+
templateUrl: 'slide-toggle-full-width-example.html',
10+
styleUrl: 'slide-toggle-full-width-example.css',
11+
imports: [MatSlideToggle],
12+
})
13+
export class SlideToggleFullWidthExample {}

src/dev-app/slide-toggle/slide-toggle-demo.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626

2727
<mat-slide-toggle aria-label="Toggle only" hideLabel color="primary" [(ngModel)]="firstToggle" />
2828

29+
<p>With full width</p>
30+
<div class="demo-full-width-container">
31+
<mat-slide-toggle fullWidth labelPosition="before" [(ngModel)]="firstToggle">Full Width Before</mat-slide-toggle>
32+
<mat-slide-toggle fullWidth labelPosition="after" [(ngModel)]="firstToggle">Full Width After</mat-slide-toggle>
33+
</div>
34+
2935
<p>Example where the slide toggle is required inside of a form.</p>
3036

3137
<form #form="ngForm" (ngSubmit)="onFormSubmit()">

src/dev-app/slide-toggle/slide-toggle-demo.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@
77
margin: 6px 0;
88
}
99
}
10+
11+
.demo-full-width-container {
12+
width: 300px;
13+
border: 1px solid #ccc;
14+
padding: 16px;
15+
}

src/material/slide-toggle/slide-toggle.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,13 @@ If you don't want the label to appear next to the slide-toggle, you can use
1313
[`aria-labelledby`](https://www.w3.org/TR/wai-aria/states_and_properties#aria-labelledby) to
1414
specify an appropriate label.
1515

16+
### Full-width slide-toggle
17+
The `fullWidth` input can be used to make the slide-toggle stretch to fill its container.
18+
When applied, the slide-toggle will distribute the switch and the label to opposite ends of the
19+
container.
20+
21+
<!-- example(slide-toggle-full-width) -->
22+
1623
### Use with `@angular/forms`
1724
`<mat-slide-toggle>` is compatible with `@angular/forms` and supports both `FormsModule`
1825
and `ReactiveFormsModule`.

src/material/slide-toggle/slide-toggle.scss

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,25 @@ $fallbacks: m3-slide-toggle.get-tokens();
557557
}
558558
}
559559

560+
.mat-slide-toggle-full-width {
561+
width: 100%;
562+
563+
.mat-internal-form-field {
564+
width: 100%;
565+
justify-content: space-between;
566+
567+
label {
568+
margin: 0;
569+
flex-grow: 1;
570+
text-align: end;
571+
}
572+
}
573+
574+
.mdc-form-field--align-end label {
575+
text-align: start;
576+
}
577+
}
578+
560579
// Element used to provide a larger tap target for users on touch devices.
561580
.mat-mdc-slide-toggle-touch-target {
562581
position: absolute;

src/material/slide-toggle/slide-toggle.spec.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,16 @@ describe('MatSlideToggle without forms', () => {
374374

375375
expect(slideToggle.checked).toBe(false);
376376
});
377+
378+
it('should add the full-width class if fullWidth is true', () => {
379+
expect(slideToggleElement.classList).not.toContain('mat-slide-toggle-full-width');
380+
381+
slideToggle.fullWidth = true;
382+
fixture.changeDetectorRef.markForCheck();
383+
fixture.detectChanges();
384+
385+
expect(slideToggleElement.classList).toContain('mat-slide-toggle-full-width');
386+
});
377387
});
378388

379389
describe('custom template', () => {

0 commit comments

Comments
 (0)