Toggle
The <smart-toggle> component provides a boolean on/off control. It follows the Base + Standard + Wrapper pattern with an InjectionToken-based extension mechanism. The abstract ToggleBaseComponent defines the shared API — value (two-way ModelSignal<boolean>), disabled, optional IToggleOptions, cssClass (alias class), and a toggle() method that flips the value while respecting the disabled state. ToggleStandardComponent is a barebones placeholder concrete implementation. ToggleComponent is the public wrapper that renders ToggleStandardComponent by default and accepts a custom replacement via TOGGLE_STANDARD_COMPONENT_TOKEN.
Usage
<smart-toggle [options]="options" [(value)]="emailNotifications" />
Components
ToggleComponent (<smart-toggle>)
Main wrapper component. Renders ToggleStandardComponent by default. When TOGGLE_STANDARD_COMPONENT_TOKEN is provided, renders the injected component via NgComponentOutlet.
ToggleStandardComponent (<smart-toggle-standard>)
Barebones native-HTML implementation. Renders a <span class="smart-toggle" data-label-position="…"> containing a minimal <input type="checkbox"> bound to value and disabled, with the external cssClass applied to the input element. options.label renders in a <label class="smart-toggle-label" for="…"> associated with the checkbox (so it is the accessible name), and options.description in a <span class="smart-toggle-description"> referenced by the checkbox's aria-describedby. Both live in a <span class="smart-toggle-text" data-role="text"> placed after the checkbox, or before it when options.labelPosition === 'left' (default 'right'). options.ariaLabel is applied as the checkbox's aria-label only when there is no label. It does not include Tailwind UI styling.
TogglePresetComponent (<smart-toggle-preset>)
Styled variation that extends ToggleBaseComponent and is a drop-in replacement for ToggleStandardComponent. Register it via TOGGLE_STANDARD_COMPONENT_TOKEN to restyle every <smart-toggle>, or use the <smart-toggle-preset> selector directly. It renders the Preline default switch: a hidden, accessible <input type="checkbox"> (with peer sr-only) drives the track / thumb visuals through peer-checked / peer-disabled states, while the value model holds the checked state (updated via the checkbox change event). Honors options.label and options.description (rendered beside the switch), options.labelPosition ('left' | 'right', default 'right'), options.ariaLabel (forwarded to the checkbox), and disabled. All classes are smart:-prefixed Tailwind with explicit dark: variants. The class recipes live in preset/preset-classes.util.ts (getToggleContainerClasses, getToggleSwitchClasses, getToggleTrackClasses, getToggleThumbClasses, getToggleTextWrapClasses, getToggleLabelClasses, getToggleDescriptionClasses).
Because
ToggleComponentrenders injected components viaNgComponentOutlet(which passes inputs by canonical name),TogglePresetComponentoverridescssClassasinput<string>('')without theclassalias. Bind it as[cssClass]when using the<smart-toggle-preset>selector directly, or just passclasson<smart-toggle>(the wrapper forwards it). Note that the Preline doc's size, soft-color, rounded, icon, tooltip, and validation-state variants are not exposed, becauseIToggleOptionshas no size/variant/color fields; the preset renders the default medium pill switch in the primary (blue) color.
ToggleBaseComponent (abstract)
Abstract base directive for extending custom toggle implementations. Exposes value as a two-way ModelSignal<boolean> (default false), disabled as an InputSignal<boolean> (default false), options as an InputSignal<IToggleOptions | undefined>, cssClass as an InputSignal<string> (with alias class), and a toggle() method that calls value.set(!value()) when disabled() is false.
API
Inputs
| Input | Type | Default | Description |
|---|---|---|---|
value | ModelSignal<boolean> | false | Toggle on/off state (two-way bindable) |
disabled | InputSignal<boolean> | false | Whether the toggle is disabled |
options | InputSignal<IToggleOptions | undefined> | - | Optional configuration (label, description, ariaLabel, position) |
class | InputSignal<string> | '' | External CSS classes (alias for cssClass) |
IToggleOptions
Both ToggleStandardComponent and TogglePresetComponent honour every property: label (the checkbox's accessible name — a <label for> in the standard), description (referenced by aria-describedby in the standard), labelPosition ('left' puts the text before the switch, otherwise it goes after — default 'right') and ariaLabel (the standard uses it only when there is no visible label; set it for label-less toggles).
TOGGLE_STANDARD_COMPONENT_TOKEN
InjectionToken that allows replacing the default ToggleStandardComponent with a custom implementation. Provide a Type<ToggleBaseComponent> to override.
Extending the base class
import {
ChangeDetectionStrategy,
Component,
computed,
input,
ViewEncapsulation,
} from '@angular/core';
import {
IToggleOptions,
TOGGLE_STANDARD_COMPONENT_TOKEN,
ToggleBaseComponent,
ToggleComponent,
} from '@smartsoft001/angular';
@Component({
selector: 'docs-custom-toggle',
template: `
<label [class]="containerClasses()">
@if (options()?.labelPosition === 'left' && options()?.label) {
<span class="docs-toggle__label">{{ options()!.label }}</span>
}
<input
type="checkbox"
class="docs-toggle__input"
[checked]="value()"
[disabled]="disabled()"
[attr.aria-label]="options()?.ariaLabel ?? null"
(change)="onChange($event)"
/>
@if (options()?.labelPosition !== 'left' && options()?.label) {
<span class="docs-toggle__label">{{ options()!.label }}</span>
}
@if (options()?.description) {
<span class="docs-toggle__description">{{
options()!.description
}}</span>
}
</label>
`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CustomToggleComponent extends ToggleBaseComponent {
// NgComponentOutlet passes 'cssClass' by canonical name, not the 'class' alias.
override cssClass = input<string>('');
containerClasses = computed(() =>
[
'docs-toggle',
`docs-toggle--label-${this.options()?.labelPosition ?? 'right'}`,
this.disabled() ? 'docs-toggle--disabled' : '',
this.cssClass(),
]
.filter(Boolean)
.join(' '),
);
// A change handler reads the checkbox state; a click handler would instead
// call the inherited toggle(), which already respects `disabled`.
protected onChange(event: Event): void {
this.value.set((event.target as HTMLInputElement).checked);
}
}
@Component({
selector: 'docs-toggle-custom-example',
changeDetection: ChangeDetectionStrategy.OnPush,
imports: [ToggleComponent],
// The token swaps the standard toggle for the custom one everywhere below
// this component, so consumers keep writing `<smart-toggle>`.
providers: [
{
provide: TOGGLE_STANDARD_COMPONENT_TOKEN,
useValue: CustomToggleComponent,
},
],
// NgComponentOutlet forwards inputs only, so the [(value)] write-back stays
// silent here and `enabled` below is the initial state.
template: `<smart-toggle [value]="enabled" [options]="options" />`,
})
export class ToggleCustomExampleComponent {
enabled = false;
options: IToggleOptions = {
label: 'Allow notifications',
description: 'Send me an email when someone comments on my work.',
labelPosition: 'right',
ariaLabel: 'Allow notifications',
};
}
Source
The component lives in packages/shared/angular/src/lib/components/toggle and is documented for Claude Code by the angular-components-toggle skill.