Basic switch
Use a switch for immediate on/off settings where the current state should be visible without opening another surface.
Icons by @ng-icons/tabler-icons
The component library does not provide icons.
Native checkbox-based toggle control for boolean settings.
Preview
TS
import { FormControl, ReactiveFormsModule } from '@angular/forms';
import { FrSwitchModule } from '@frame-ui-ng/components/switch';
notificationsControl = new FormControl(true, { nonNullable: true });HTML
<label frSwitchField>
<input frSwitch type="checkbox" [formControl]="notificationsControl" />
<span frSwitchContent>
<span frSwitchLabel>Enable release notifications</span>
<span frSwitchDescription>Notify workspace members when a rollout completes.</span>
</span>
</label>Use a switch for immediate on/off settings where the current state should be visible without opening another surface.
Use the default size for settings pages and the small size when switches sit inside denser toolbars or filters.
Disable a switch when a policy or upstream dependency temporarily prevents changes while still exposing the current state.
Reactive forms can drive required confirmation flows directly, so the switch track and error text stay synchronized with Angular validation.
Scope switch token overrides to a wrapper when a settings area needs different spacing, a larger track, or a more pronounced checked state without changing the primitive structure.
Hover the field wrapper, switch control, content stack, label, description, or error copy to inspect the tokens that govern sizing, spacing, checked state, and validation treatment.
Use these CSS custom properties to tune switch sizing, checked-state surfaces, thumb treatment, field spacing, and helper-text typography without changing the primitive structure.
SCSS
--frame-switch-field-gap: 0.75rem;
--frame-switch-field-color: var(--frame-foreground);
--frame-switch-field-disabled-color: var(--frame-muted-foreground);
--frame-switch-content-gap: 0.25rem;
--frame-switch-label-font-size: 0.875rem;
--frame-switch-label-font-weight: 600;
--frame-switch-description-color: var(--frame-muted-foreground);
--frame-switch-description-font-size: 0.8125rem;
--frame-switch-error-color: var(--frame-destructive);
--frame-switch-error-font-size: 0.8125rem;
--frame-switch-width: 2.25rem;
--frame-switch-height: 1.25rem;
--frame-switch-thumb-size: 1rem;
--frame-switch-padding: 0.125rem;
--frame-switch-sm-width: 1.75rem;
--frame-switch-sm-height: 1rem;
--frame-switch-sm-thumb-size: 0.75rem;
--frame-switch-radius: 999px;
--frame-switch-bg: var(--frame-input);
--frame-switch-hover-bg: color-mix(in srgb, var(--frame-input) 82%, var(--frame-foreground));
--frame-switch-checked-bg: var(--frame-primary);
--frame-switch-checked-hover-bg: color-mix(in srgb, var(--frame-primary) 88%, var(--frame-foreground));
--frame-switch-thumb-bg: var(--frame-background);
--frame-switch-thumb-shadow: 0 1px 2px rgb(0 0 0 / 0.22);
--frame-switch-border-shadow: inset 0 0 0 1px color-mix(in srgb, var(--frame-border) 70%, transparent);
--frame-switch-checked-border-shadow: inset 0 0 0 1px color-mix(in srgb, var(--frame-primary) 80%, var(--frame-border));
--frame-switch-focus-shadow: 0 0 0 3px color-mix(in srgb, var(--frame-ring) 28%, transparent);
--frame-switch-invalid-border: color-mix(in srgb, var(--frame-destructive) 65%, var(--frame-border));
--frame-switch-invalid-shadow: inset 0 0 0 1px color-mix(in srgb, var(--frame-destructive) 40%, transparent), 0 0 0 3px color-mix(in srgb, var(--frame-destructive) 14%, transparent);
--frame-switch-disabled-opacity: 0.5;
--frame-switch-transition-duration: 160ms;
--frame-switch-transition-easing: cubic-bezier(0.16, 1, 0.3, 1);