Switch
A toggle switch that works with Angular forms.
import { … } from '@inlaylab/ivorie/switch'On: false
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { IvSwitch } from '@inlaylab/ivorie/switch';
@Component({
selector: 'demo-switch',
imports: [IvSwitch],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="flex flex-col items-center gap-3">
<iv-switch [(checked)]="enabled" aria-label="Notifications" />
<p class="text-muted-foreground text-sm">On: {{ enabled() }}</p>
</div>
`,
})
export default class SwitchDemo {
protected readonly enabled = signal(false);
}
Installation
npx ivorie add switchimport { … } from '@inlaylab/ivorie/switch'A native <button role="switch"> that works as a form control. It supports ngModel, reactive forms and plain two-way binding.
Usage
import { IvSwitch } from '@inlaylab/ivorie/switch';<iv-switch [(checked)]="enabled" aria-label="Notifications" />Examples
With ngModel
Value: true
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { IvSwitch } from '@inlaylab/ivorie/switch';
@Component({
selector: 'demo-switch-ngmodel',
imports: [FormsModule, IvSwitch],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="flex flex-col items-center gap-3">
<iv-switch [(ngModel)]="notifications" aria-label="Notifications" />
<p class="text-muted-foreground text-sm">Value: {{ notifications() }}</p>
</div>
`,
})
export default class SwitchNgmodelDemo {
protected readonly notifications = signal(true);
}
Reactive forms
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { IvSwitch } from '@inlaylab/ivorie/switch';
@Component({
selector: 'demo-switch-reactive-forms',
imports: [ReactiveFormsModule, IvSwitch],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<form [formGroup]="form" class="flex flex-col items-center gap-3">
<iv-switch formControlName="darkMode" aria-label="Dark mode" />
<p class="text-muted-foreground text-sm">Value: {{ form.value.darkMode }}</p>
</form>
`,
})
export default class SwitchReactiveFormsDemo {
protected readonly form = new FormGroup({ darkMode: new FormControl(false) });
}
With label
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { IvSwitch } from '@inlaylab/ivorie/switch';
@Component({
selector: 'demo-switch-with-label',
imports: [IvSwitch],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<label class="flex cursor-pointer items-center gap-2 text-sm font-medium">
<iv-switch [(checked)]="emailAlerts" />
Email alerts
</label>
`,
})
export default class SwitchWithLabelDemo {
protected readonly emailAlerts = signal(true);
}
Small
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IvSwitch } from '@inlaylab/ivorie/switch';
@Component({
selector: 'demo-switch-small',
imports: [IvSwitch],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="flex items-center gap-4">
<iv-switch size="sm" [checked]="true" aria-label="Small" />
<iv-switch aria-label="Default" />
</div>
`,
})
export default class SwitchSmallDemo {}
Disabled
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { IvSwitch } from '@inlaylab/ivorie/switch';
@Component({
selector: 'demo-switch-disabled',
imports: [IvSwitch],
changeDetection: ChangeDetectionStrategy.OnPush,
template: `
<div class="flex items-center gap-4">
<iv-switch [disabled]="true" aria-label="Off, disabled" />
<iv-switch [checked]="true" [disabled]="true" aria-label="On, disabled" />
</div>
`,
})
export default class SwitchDisabledDemo {}
API
Every part also accepts class.
iv-switch
| Name | Type | Default | Description |
|---|---|---|---|
checked |
boolean |
false |
On/off state. Bind with [(checked)]. |
size |
'default' | 'sm' |
'default' |
Track and thumb size. |
disabled |
boolean |
false |
Blocks interaction. Also disabled when the form control is disabled. |
id |
string | null |
null |
Set on the inner button, so <label for> works. |
aria-label |
string | null |
null |
Set on the inner button. |
aria-labelledby |
string | null |
null |
Set on the inner button. |
Outputs:
| Name | Payload | Description |
|---|---|---|
checkedChange |
boolean |
Emits after the user toggles. |
Accessibility
- Renders
<button type="button" role="switch">. The host isdisplay: contents. aria-checkedfollows the checked state.SpaceandEntertoggle.Tabmoves focus.- A wrapping
<label>and<label for>both work. - Disabled uses the native
disabledattribute. - An invisible padded area makes the hit target larger.
Notes
ngModelandformControlNameneedFormsModuleorReactiveFormsModule.- The button and thumb have
data-state(checkedorunchecked) anddata-disabled. - The form marks the control touched on blur. Setting the value from the form does not emit
checkedChange.