# Toggle

- Entry point: `@koobiq/components/toggle`
- NgModule: `KbqToggleModule`
- Page: https://koobiq.io/en/components/toggle/overview

## Overview

**State toggle button:** on or off. For example, Wi-Fi is turned on or off on a phone.

**Example: Toggle** (`toggle-overview`)

```ts toggle-overview-example.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-overview-example',
    imports: [KbqToggleModule],
    template: `
        <kbq-toggle [checked]="value()" (change)="value.set($event.checked)">Wi-Fi</kbq-toggle>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-align-center-center layout-row'
    }
})
export class ToggleOverviewExample {
    protected readonly value = signal(false);
}
```

### Properties

#### Disabled state

**Example: Toggle Disabled** (`toggle-disabled`)

```ts toggle-disabled-example.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-disabled-example',
    imports: [KbqToggleModule],
    template: `
        <kbq-toggle [checked]="value()" [disabled]="true" (change)="value.set($event.checked)">Vibration</kbq-toggle>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-align-center-center layout-row'
    }
})
export class ToggleDisabledExample {
    protected readonly value = signal(false);
}
```

#### Error

**Example: Toggle Error** (`toggle-error`)

```ts toggle-error-example.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { KbqComponentColors } from '@koobiq/components/core';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-error-example',
    imports: [KbqToggleModule],
    template: `
        <kbq-toggle [checked]="value()" [color]="color" (change)="value.set($event.checked)">Vibration</kbq-toggle>
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-align-center-center layout-row'
    }
})
export class ToggleErrorExample {
    protected readonly value = signal(false);
    protected readonly color = KbqComponentColors.Error;
}
```

#### Validation

To show a validation error, bind the toggle to a form control, apply `Validators.requiredTrue`, and put the error text in a `kbq-error` inside the toggle.

To show the error at another moment, pass a matcher to the `errorStateMatcher` input. The matchers are described in the [Validation guide](https://koobiq.io/en/other/validation.md).

**Example: Toggle validation** (`toggle-validation`)

```ts toggle-validation-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms';
import { KbqError, KbqHint } from '@koobiq/components/form-field';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-validation-example',
    imports: [ReactiveFormsModule, KbqToggleModule, KbqHint, KbqError],
    template: `
        <kbq-toggle class="example-toggle-validation" [formControl]="backup">
            Automatic backup
            <kbq-hint>Turn it off to see the error</kbq-hint>
            <kbq-error>Required by the security policy of your organization</kbq-error>
        </kbq-toggle>
    `,
    // A fixed width keeps the centered example in place when the error, wider than the label, appears.
    styles: `
        .example-toggle-validation {
            width: 320px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-align-center-center layout-row layout-padding-l'
    }
})
export class ToggleValidationExample {
    protected readonly backup = new FormControl(true, { nonNullable: true, validators: Validators.requiredTrue });
}
```

#### Indeterminate state

This state is used to reflect partial selection or uncertainty.

**Example: Toggle Indeterminate** (`toggle-indeterminate`)

```ts toggle-indeterminate-example.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-indeterminate-example',
    imports: [KbqToggleModule],
    template: `
        <kbq-toggle [checked]="checked()" [indeterminate]="indeterminate()" />
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-align-center-center layout-row'
    }
})
export class ToggleIndeterminateExample {
    protected readonly checked = signal(false);
    protected readonly indeterminate = signal(true);
}
```

#### Loading

While loading, the toggle looks inactive, ignores clicks, but stays focusable.

**Example: Toggle Loading** (`toggle-loading`)

```ts toggle-loading-example.ts
import { ChangeDetectionStrategy, Component, signal } from '@angular/core';
import { KbqToggleChange, KbqToggleModule } from '@koobiq/components/toggle';
import { timer } from 'rxjs';

@Component({
    selector: 'toggle-loading-example',
    imports: [KbqToggleModule],
    template: `
        <kbq-toggle [checked]="checked()" [loading]="loading" (change)="handleToggle($event)" />
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-margin-5xl layout-row layout-align-center-center'
    }
})
export class ToggleLoadingExample {
    protected readonly checked = signal(false);
    protected loading = false;

    handleToggle({ checked }: KbqToggleChange) {
        this.loading = true;
        timer(3000).subscribe(() => {
            this.loading = false;
            this.checked.set(checked);
        });
    }
}
```

#### Big

Use the `big` input to render the toggle with the enlarged typography of the label and the hint. The switch itself keeps its size.

### Content

#### Hint

**Example: Toggle With Hint** (`toggle-with-hint`)

```ts toggle-with-hint-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqFormFieldModule } from '@koobiq/components/form-field';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-with-hint-example',
    imports: [KbqToggleModule, KbqFormFieldModule],
    template: `
        <div class="example-toggle-with-hint__container layout-align-center-start layout-column layout-gap-s">
            <div>Touch</div>
            <kbq-toggle>
                Tap to wake
                <kbq-hint>Wake the screen when you tap on the display</kbq-hint>
            </kbq-toggle>
            <kbq-toggle>
                Shake to undo
                <kbq-hint>
                    If you tend to share your phone by accident, you can disable Shake to Undo to prevent the Undo alert
                    from appearing.
                </kbq-hint>
            </kbq-toggle>
            <kbq-toggle>
                Vibration
                <kbq-hint>
                    When this witch is off, all vibration on your phone will be disabled, including those for
                    earthquake, tsunami and other emergency alerts.
                </kbq-hint>
            </kbq-toggle>
        </div>
    `,
    styles: `
        .example-toggle-with-hint__container {
            max-width: 320px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-align-center-center layout-row layout-padding-top-l layout-padding-bottom-3xl'
    }
})
export class ToggleWithHintExample {}
```

#### Label on the left

The toggle is placed to the right of the field name and hint block. Use `labelPosition="left"` for this layout, the default value is `right`.

**Example: Toggle multiline example** (`toggle-multiline`)

```ts toggle-multiline-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqFormFieldModule } from '@koobiq/components/form-field';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-multiline-example',
    imports: [KbqToggleModule, KbqFormFieldModule],
    template: `
        <div
            class="example-toggle-multiline__container layout-align-center-start layout-column layout-gap-s layout-padding-top-l layout-padding-left-l layout-padding-right-l layout-padding-bottom-xl "
        >
            <kbq-toggle labelPosition="left">
                Shake to undo
                <kbq-hint>
                    If you tend to share your phone by accident, you can disable
                    <span class="kbq-text-compact-strong">Shake to Undo</span>
                    to prevent the
                    <span class="kbq-text-compact-strong">Undo</span>
                    alert from appearing.
                </kbq-hint>
            </kbq-toggle>
        </div>
    `,
    styles: `
        .example-toggle-multiline__container {
            max-width: 320px;
            background: var(--kbq-background-card);
            box-shadow: var(--kbq-shadow-card);
            border-radius: var(--kbq-size-border-radius);
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-align-center-center layout-row layout-margin-top-l layout-margin-bottom-l'
    }
})
export class ToggleMultilineExample {}
```

The toggle can be placed to the right and on the same line after the label.

**Example: Toggle Label Left** (`toggle-label-left`)

```ts toggle-label-left-example.ts
import { ChangeDetectionStrategy, Component } from '@angular/core';
import { KbqToggleModule } from '@koobiq/components/toggle';

@Component({
    selector: 'toggle-label-left-example',
    imports: [KbqToggleModule],
    template: `
        <div class="example-toggle-label-left__container layout-align-center-start layout-column layout-gap-s">
            <kbq-toggle labelPosition="left" [checked]="true">Tap to wake</kbq-toggle>
            <kbq-toggle labelPosition="left">Shake to undo</kbq-toggle>
            <kbq-toggle labelPosition="left">Vibration</kbq-toggle>
        </div>
    `,
    styles: `
        .example-toggle-label-left__container {
            margin-bottom: 28px;
        }
    `,
    changeDetection: ChangeDetectionStrategy.OnPush,
    host: {
        class: 'layout-align-center-center layout-row layout-gap-s layout-margin-top-xxl'
    }
})
export class ToggleLabelLeftExample {}
```

### Accessibility

Without a visible label, describe the toggle with `aria-label` or point `aria-labelledby` at an existing caption. A projected `kbq-hint` is exposed as the description of the control and is not part of its name.

The `name` and `value` inputs are forwarded to the underlying `<input type="checkbox">`, so the toggle is serialized by native form submission.

### Recommendations

- Use a toggle for instant switching of settings that do not require confirmation. For example, changes are applied immediately without a “Save” button. If saving requires submitting a form, use a [checkbox](https://koobiq.io/en/components/checkbox.md).
- Do not use a toggle if the choice options do not fit binary logic: on or off, yes or no.
- Use `clickAction` (or the `KBQ_CHECKABLE_CLICK_ACTION` token for the whole application) to change what a click does: `check-indeterminate` is the default, `check` keeps the mixed state, and `noop` leaves the state to the application.

## API

### Components

#### KbqToggleComponent (component)

A switch for turning an option on or off.

To show a validation error, put its text in a `kbq-error` inside the toggle bound to a form control.

```ts
@Component({ selector: 'kbq-toggle', exportAs: 'kbqToggle' })
class KbqToggleComponent extends KbqColorDirective implements CanUpdateErrorState {
    readonly errorStateMatcher = input<ErrorStateMatcher>();
    readonly big = input<boolean>(false);
    readonly labelPosition = input<ToggleLabelPositionType>('right');
    readonly ariaLabel = input<string>('', { alias: 'aria-label' });
    readonly ariaLabelledby = input<string | null>(null, {
        alias: 'aria-labelledby'
    });
    id = input<string | undefined>();
    readonly name = input<string | null>(null);
    readonly value = input<string | undefined>();
    disabled = input<boolean | undefined>();
    checked = input<boolean | undefined>();
    indeterminate = model<boolean | undefined>();
    readonly loading = input<boolean>(false);
    clickAction = input<KbqToggleClickAction | undefined>();
    readonly color = input<T | null | undefined>();
    readonly change = output<KbqToggleChange>();
    readonly errorState: Signal<boolean>;
    readonly inputElement: Signal<ElementRef<HTMLInputElement>>;
    get inputId(): string;
    get colorClassName(): string;
    updateErrorState(): void;
    focus(): void;
    getAriaChecked(): KbqCheckedState;
    onChangeEvent(event: Event): void;
    /** @deprecated */
    onLabelTextChange(): void;
    onInputClick(event: MouseEvent): void;
    setDefaultColor(color: T): void;
}
```

- `[errorStateMatcher]`: `ErrorStateMatcher` — An object used to control when the error state is shown.
- `[(indeterminate)]`: `boolean | undefined` — Whether the toggle is indeterminate. This is also known as "mixed" mode and can be used to
  represent a checkbox with three states, e.g. a checkbox that represents a nested list of
  checkable items. Note that whenever checkbox is manually clicked, indeterminate is immediately
  set to false.
- `[loading]`: `boolean` — Property for manually set loading state.
- `[clickAction]`: `KbqToggleClickAction | undefined` — Defines the behavior when a user clicks on the toggle.
- `[color]`: `T | null | undefined` — Color of the component. A value set in code holds until the input changes, and the default color is used
  while both are unset or falsy.
- `errorState`: `Signal<boolean>` — Whether the toggle is in an error state.
- `colorClassName`: `string` — current class name of color
- `updateErrorState()`: `void` — Updates the error state based on the error state matcher.
- `onLabelTextChange()`: `void` — Does nothing: the view reads nothing from the label, so a change of it needs no re-check.

  Deprecated: Kept for back-compatibility. Will be removed in 22.0.0.
- `setDefaultColor()`: `void` — this color will be used as a default value. For example [color]="'' | false | undefined | null".

### Classes

#### KbqToggleChange (class)

Change event object emitted by `KbqToggleComponent`.

```ts
class KbqToggleChange {
    source: KbqToggleComponent;
    checked: boolean;
}
```

- `source`: `KbqToggleComponent` — The source toggle of the event.
- `checked`: `boolean` — The new `checked` value of the toggle.

### Types

#### KbqToggleClickAction (type)

Toggle click action when user click on input element. Alias of `KbqCheckableClickAction`.

```ts
type KbqToggleClickAction = KbqCheckableClickAction;
```

#### ToggleLabelPositionType (type)

Position of the label relative to the switch.

```ts
type ToggleLabelPositionType = 'left' | 'right';
```
