# TOTP

Use `ui-totp` for two-factor authentication, device verification, SMS codes, and short PIN-style confirmation flows. It inherits the shared field API for labels, help text, size, variant, readonly, disabled, and validation messaging while adding grouped digit inputs and verification-specific interaction behavior.

## Import
```ts
import { TotpComponent } from 'ui';
```

## Basic verification input
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TotpComponent } from 'ui';

@Component({
  selector: 'app-totp-basic-demo',
  standalone: true,
  imports: [FormsModule, TotpComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div
        style="flex:1 1 18rem;min-width:16rem;display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Authenticator app code</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Good default for standard 6-digit verification.
          </div>
        </div>

        <ui-totp
          label="Verification code"
          helpText="Enter the 6-digit code from your authenticator app."
        />
      </div>

      <div
        style="flex:1 1 18rem;min-width:16rem;display:flex;flex-direction:column;gap:1rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="display:flex;flex-direction:column;gap:0.25rem">
          <div style="font-size:0.9375rem;font-weight:600">Pre-filled example</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Shows how pasted or restored values distribute across the inputs.
          </div>
        </div>

        <ui-totp
          label="TOTP code"
          helpText="You can paste the full code or type digit by digit."
          [(ngModel)]="code"
          [ngModelOptions]="{ standalone: true }"
        />
      </div>
    </div>
  `,
})
export class TotpBasicDemoComponent {
  protected code = '123456';
}
```

## Digit count and scale
```ts
import { Component } from '@angular/core';
import { TotpComponent } from 'ui';

@Component({
  selector: 'app-totp-digits-demo',
  standalone: true,
  imports: [TotpComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-totp
          label="PIN code"
          [digitsCount]="4"
          size="small"
          helpText="Useful for shorter confirmation or device unlock flows."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-totp
          label="Standard 2FA"
          [digitsCount]="6"
          size="medium"
          helpText="Most authenticator and SMS verification flows use 6 digits."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-totp
          label="Extended recovery code"
          [digitsCount]="8"
          size="large"
          helpText="Longer codes fit higher-assurance verification or backup flows."
        />
      </div>
    </div>
  `,
})
export class TotpDigitsDemoComponent {}
```

## Appearance and size
```ts
import { Component } from '@angular/core';
import { TotpComponent } from 'ui';

@Component({
  selector: 'app-totp-appearance-demo',
  standalone: true,
  imports: [TotpComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:44rem">
      <div
        style="display:flex;flex-direction:column;gap:0.875rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="font-size:0.9375rem;font-weight:600">Filled verification surface</div>
        <ui-totp
          label="Verification code"
          inputVariant="filled"
          size="medium"
          helpText="Balanced default for most auth surfaces."
        />
      </div>

      <div
        style="display:flex;flex-direction:column;gap:0.875rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="font-size:0.9375rem;font-weight:600">Alternative visual treatments</div>
        <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start">
          <div style="flex:1 1 12rem;min-width:11rem">
            <ui-totp label="Gray" inputVariant="filled-gray" size="small" />
          </div>
          <div style="flex:1 1 12rem;min-width:11rem">
            <ui-totp label="Lighter" inputVariant="filled-lighter" size="medium" />
          </div>
          <div style="flex:1 1 12rem;min-width:11rem">
            <ui-totp label="Underlined" inputVariant="underlined" size="large" />
          </div>
        </div>
      </div>
    </div>
  `,
})
export class TotpAppearanceDemoComponent {}
```

## Readonly, disabled, and error states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { TotpComponent } from 'ui';

@Component({
  selector: 'app-totp-states-demo',
  standalone: true,
  imports: [FormsModule, TotpComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-totp
          label="Readonly backup code"
          [readonly]="true"
          [(ngModel)]="readonlyCode"
          [ngModelOptions]="{ standalone: true }"
          helpText="Useful when showing a generated code without allowing edits."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-totp
          label="Disabled verification"
          [disabled]="true"
          helpText="Disabled removes interaction entirely."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-totp
          label="Incorrect code"
          [(ngModel)]="invalidCode"
          [ngModelOptions]="{ standalone: true }"
          [errorText]="invalidError"
          helpText="Example of a failed verification state."
        />
      </div>
    </div>
  `,
})
export class TotpStatesDemoComponent {
  protected readonlyCode = '654321';
  protected invalidCode = '123';

  protected get invalidError(): string {
    if (!this.invalidCode) {
      return '';
    }
    return this.invalidCode.length === 6 ? 'Invalid verification code.' : '';
  }
}
```

## Validation with reactive forms
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ButtonComponent, TotpComponent } from 'ui';

@Component({
  selector: 'app-totp-validation-demo',
  standalone: true,
  imports: [ButtonComponent, ReactiveFormsModule, TotpComponent],
  template: `
    <form
      [formGroup]="verifyForm"
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:34rem"
      (ngSubmit)="markTouched()"
    >
      <ui-totp
        label="SMS code"
        [digitsCount]="6"
        helpText="Required. Enter the full 6-digit code."
        formControlName="code"
        [errorText]="codeError"
      />

      <div style="display:flex;flex-wrap:wrap;gap:0.75rem">
        <ui-button type="submit">Validate</ui-button>
        <ui-button type="button" appearance="outline" (click)="fillExample()"
          >Use example</ui-button
        >
      </div>
    </form>
  `,
})
export class TotpValidationDemoComponent {
  protected readonly verifyForm = new FormGroup({
    code: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required, Validators.minLength(6), Validators.maxLength(6)],
    }),
  });

  protected get codeError(): string {
    const control = this.verifyForm.controls.code;
    if (!control.touched && !control.dirty) {
      return '';
    }
    if (control.hasError('required')) {
      return 'Verification code is required.';
    }
    if (control.hasError('minlength') || control.hasError('maxlength')) {
      return 'Enter all 6 digits.';
    }
    return '';
  }

  protected markTouched(): void {
    this.verifyForm.markAllAsTouched();
  }

  protected fillExample(): void {
    this.verifyForm.controls.code.setValue('482915');
    this.verifyForm.controls.code.markAsTouched();
  }
}
```

## Verification panel composition
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, TotpComponent } from 'ui';

@Component({
  selector: 'app-totp-verification-panel-demo',
  standalone: true,
  imports: [ButtonComponent, FormsModule, TotpComponent],
  template: `
    <div
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:38rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <div style="display:flex;flex-direction:column;gap:0.375rem">
        <div style="font-size:1rem;font-weight:600">Two-factor verification</div>
        <div
          style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);line-height:1.45"
        >
          A realistic verification surface combines the code input, context about where the code
          came from, and nearby next-step actions.
        </div>
      </div>

      <ui-totp
        label="Verification code"
        [(ngModel)]="code"
        [ngModelOptions]="{ standalone: true }"
        helpText="Code sent to your authenticator app for account ending in 27."
        [errorText]="panelError"
      />

      <div
        style="display:flex;gap:0.75rem;flex-wrap:wrap;align-items:center;padding:0.75rem 0.875rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:0.875rem;background:var(--color-neutral-background-rest)"
      >
        <ui-button type="button" variant="primary">Verify code</ui-button>
        <ui-button type="button" variant="secondary" appearance="outline" (click)="code = ''">
          Clear
        </ui-button>
        <ui-button type="button" appearance="subtle">Use recovery code</ui-button>
      </div>
    </div>
  `,
})
export class TotpVerificationPanelDemoComponent {
  protected code = '';

  protected get panelError(): string {
    if (!this.code) {
      return '';
    }
    return this.code.length === 6 ? '' : 'Enter all 6 digits before continuing.';
  }
}
```

## Accessibility

### Grouped input semantics
`ui-totp` exposes the digit inputs inside a container with `role="group"`. The component uses either the visible label or a fallback group label so assistive technologies announce the code entry context once and then each digit position individually.

### Keyboard and paste behavior
| Key / action | Behavior |
| --- | --- |
| Typing a digit | Fills the current input and moves focus to the next digit. |
| Backspace | Clears the current digit or moves back and clears the previous one when current is empty. |
| Arrow Left / Right | Moves between digits according to text direction. |
| Paste | Splits pasted numeric content across the remaining digit inputs. |
| Home / End | Not used; standard field navigation is digit-to-digit instead. |

### Labels and descriptions
Each digit input gets its own accessible label such as `Digit 1 of 6`, while help and error text are linked through `aria-describedby`. This keeps the grouped code understandable without forcing the user to infer position from visual layout alone.
