# Password

Use `ui-password` for sign-in, reset, and credential-management flows where masked entry, reveal actions, and password-manager compatibility matter. It inherits the shared field API for labels, help text, size, variant, readonly, disabled, and validation messaging while adding password-specific affordances.

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

## Basic password fields
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { PasswordComponent } from 'ui';

@Component({
  selector: 'app-password-basic-demo',
  standalone: true,
  imports: [FormsModule, PasswordComponent],
  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">Sign-in password</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Good default for login and short verification steps.
          </div>
        </div>

        <ui-password
          label="Password"
          placeholder="Enter your password"
          autocomplete="current-password"
          helpText="Use the password for this workspace account."
        />
      </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 secure value</div>
          <div style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)">
            Reveal and clear actions are built in when the field is editable.
          </div>
        </div>

        <ui-password
          label="App password"
          placeholder="Enter app password"
          [(ngModel)]="savedPassword"
          [ngModelOptions]="{ standalone: true }"
          helpText="Use show and clear actions directly from the field."
        />
      </div>
    </div>
  `,
})
export class PasswordBasicDemoComponent {
  protected savedPassword = 'P@ssword-2026';
}
```

## Layout, size, and variant
```ts
import { Component } from '@angular/core';
import { PasswordComponent } from 'ui';

@Component({
  selector: 'app-password-layout-demo',
  standalone: true,
  imports: [PasswordComponent],
  template: `
    <div style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:46rem">
      <div
        style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
      >
        <div style="flex:1 1 15rem;min-width:14rem">
          <ui-password
            label="Compact PIN password"
            labelPosition="above"
            size="small"
            inputVariant="filled-lighter"
            placeholder="Enter password"
          />
        </div>

        <div style="flex:1 1 15rem;min-width:14rem">
          <ui-password
            label="Admin secret"
            labelPosition="before"
            size="medium"
            inputVariant="filled-gray"
            placeholder="Enter password"
          />
        </div>
      </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">Prominent credential step</div>
        <ui-password
          label="Encryption passphrase"
          size="large"
          inputVariant="filled"
          placeholder="Create an encryption passphrase"
          helpText="Use a larger field when password creation is the primary task in the view."
        />
      </div>
    </div>
  `,
})
export class PasswordLayoutDemoComponent {}
```

## Autocomplete and reveal behavior
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { PasswordComponent } from 'ui';

@Component({
  selector: 'app-password-autocomplete-demo',
  standalone: true,
  imports: [FormsModule, PasswordComponent],
  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-password
          label="Current password"
          autocomplete="current-password"
          placeholder="Enter current password"
          helpText="Use this for sign-in and identity verification."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-password
          label="New password"
          autocomplete="new-password"
          placeholder="Create a new password"
          helpText="Use this when the user is setting or resetting a password."
        />
      </div>

      <div style="flex:1 1 16rem;min-width:15rem">
        <ui-password
          label="Readonly recovery key"
          [readonly]="true"
          [(ngModel)]="recoveryKey"
          [ngModelOptions]="{ standalone: true }"
          helpText="Readonly keeps the value visible, but reveal and clear actions stay hidden."
        />
      </div>
    </div>
  `,
})
export class PasswordAutocompleteDemoComponent {
  protected recoveryKey = 'VaultKey-48F2-Delta';
}
```

## Strength guidance
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { ButtonComponent, PasswordComponent } from 'ui';

@Component({
  selector: 'app-password-strength-demo',
  standalone: true,
  imports: [ButtonComponent, FormsModule, PasswordComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;gap:1rem;align-items:flex-start;width:100%">
      <div
        style="flex:1 1 20rem;min-width:18rem;max-width:30rem;display:flex;flex-direction:column;gap:0.875rem"
      >
        <ui-password
          label="Create password"
          placeholder="Create a strong password"
          autocomplete="new-password"
          [(ngModel)]="password"
          [ngModelOptions]="{ standalone: true }"
          [helpText]="strengthHelpText"
          [errorText]="strengthErrorText"
        />

        <div
          style="display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:0.375rem"
          aria-hidden="true"
        >
          @for (segment of [1, 2, 3, 4]; track segment) {
            <div
              style="height:0.375rem;border-radius:999px;background:color-mix(in srgb,var(--color-neutral-stroke-rest) 70%,transparent)"
            >
              <div
                [style.width]="segment <= strengthSegments ? '100%' : '0%'"
                [style.height]="'100%'"
                [style.borderRadius]="'inherit'"
                [style.transition]="'width 180ms ease, background-color 180ms ease'"
                [style.background]="strengthColor"
              ></div>
            </div>
          }
        </div>

        <div
          style="display:flex;justify-content:space-between;gap:1rem;font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)"
        >
          <span>Strength</span>
          <strong [style.color]="strengthColor" style="font-weight:600">{{ strengthLabel }}</strong>
        </div>
      </div>

      <div
        style="flex:0 0 17rem;display:flex;flex-direction:column;gap:0.75rem;min-width:15rem;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <p
          style="margin:0;font-size:0.75rem;font-weight:600;letter-spacing:0.06em;text-transform:uppercase;color:var(--color-neutral-foreground2-rest)"
        >
          Strength checks
        </p>

        <div
          style="display:flex;flex-direction:column;gap:0.45rem;font-size:0.875rem;line-height:1.4"
        >
          @for (check of checks; track check.label) {
            <div style="display:flex;justify-content:space-between;gap:1rem">
              <span style="color:var(--color-neutral-foreground2-rest)">{{ check.label }}</span>
              <strong style="font-weight:600;color:var(--color-neutral-foreground-rest)">{{
                check.passed ? 'Yes' : 'No'
              }}</strong>
            </div>
          }
        </div>

        <div
          style="display:flex;gap:0.75rem;flex-wrap:wrap;align-items:center;padding-top:0.75rem;border-top:1px solid color-mix(in srgb,var(--color-neutral-stroke-rest) 65%,transparent)"
        >
          <ui-button type="button" appearance="outline" (click)="useExample('VaultTeam2026!')">
            Use strong example
          </ui-button>
        </div>
      </div>
    </div>
  `,
})
export class PasswordStrengthDemoComponent {
  protected password = '';

  protected get checks() {
    return [
      { label: '8+ characters', passed: this.password.length >= 8 },
      { label: 'Uppercase', passed: /[A-Z]/.test(this.password) },
      { label: 'Number', passed: /\d/.test(this.password) },
      { label: 'Special character', passed: /[^A-Za-z0-9]/.test(this.password) },
    ];
  }

  protected get strengthSegments(): number {
    return this.checks.filter(check => check.passed).length;
  }

  protected get strengthColor(): string {
    if (this.strengthSegments <= 1) {
      return 'var(--color-shared-red-foreground)';
    }
    if (this.strengthSegments <= 3) {
      return 'var(--color-shared-orange-foreground)';
    }
    return 'var(--color-shared-green-foreground)';
  }

  protected get strengthLabel(): string {
    if (!this.password) {
      return 'Not started';
    }
    if (this.strengthSegments <= 1) {
      return 'Weak';
    }
    if (this.strengthSegments <= 3) {
      return 'Medium';
    }
    return 'Strong';
  }

  protected get strengthErrorText(): string {
    if (!this.password || this.strengthSegments >= 4) {
      return '';
    }
    return 'Add length, uppercase, numbers, and symbols before saving.';
  }

  protected get strengthHelpText(): string {
    if (!this.password) {
      return 'Use at least 8 characters, uppercase, numbers, and symbols.';
    }
    if (this.strengthSegments <= 1) {
      return 'Weak password.';
    }
    if (this.strengthSegments <= 3) {
      return 'Almost there. Add one more requirement.';
    }
    return 'Strong password.';
  }

  protected useExample(value: string): void {
    this.password = value;
  }
}
```

## Confirmation and matching
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ButtonComponent, PasswordComponent } from 'ui';

@Component({
  selector: 'app-password-confirmation-demo',
  standalone: true,
  imports: [ButtonComponent, PasswordComponent, ReactiveFormsModule],
  template: `
    <form
      [formGroup]="passwordForm"
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:34rem"
      (ngSubmit)="markTouched()"
    >
      <ui-password
        label="New password"
        placeholder="Create password"
        autocomplete="new-password"
        formControlName="password"
        helpText="Use at least 8 characters."
        [errorText]="passwordError"
      />

      <ui-password
        label="Confirm password"
        placeholder="Repeat password"
        autocomplete="new-password"
        formControlName="confirmPassword"
        [helpText]="confirmHelpText"
        [errorText]="confirmError"
      />

      <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 PasswordConfirmationDemoComponent {
  protected readonly passwordForm = new FormGroup({
    password: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required, Validators.minLength(8)],
    }),
    confirmPassword: new FormControl('', {
      nonNullable: true,
      validators: [Validators.required],
    }),
  });

  protected get passwordError(): string {
    const control = this.passwordForm.controls.password;
    if (!control.touched && !control.dirty) {
      return '';
    }
    if (control.hasError('required')) {
      return 'Password is required.';
    }
    if (control.hasError('minlength')) {
      return 'Use at least 8 characters.';
    }
    return '';
  }

  protected get confirmError(): string {
    const control = this.passwordForm.controls.confirmPassword;
    if (!control.touched && !control.dirty) {
      return '';
    }
    if (control.hasError('required')) {
      return 'Confirm the password.';
    }
    if (control.value && control.value !== this.passwordForm.controls.password.value) {
      return 'Passwords do not match.';
    }
    return '';
  }

  protected get confirmHelpText(): string {
    const confirmValue = this.passwordForm.controls.confirmPassword.value;
    if (!confirmValue) {
      return 'Repeat the password exactly.';
    }
    return confirmValue === this.passwordForm.controls.password.value
      ? 'Passwords match.'
      : 'The value must match the first field.';
  }

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

  protected fillExample(): void {
    this.passwordForm.setValue({
      password: 'TeamPortal2026!',
      confirmPassword: 'TeamPortal2026!',
    });
    this.passwordForm.markAllAsTouched();
  }
}
```

## Reset panel composition
```ts
import { Component } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ButtonComponent, PasswordComponent } from 'ui';

@Component({
  selector: 'app-password-reset-panel-demo',
  standalone: true,
  imports: [ButtonComponent, PasswordComponent, ReactiveFormsModule],
  template: `
    <form
      [formGroup]="resetForm"
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:40rem;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">Reset workspace password</div>
        <div
          style="font-size:0.875rem;color:var(--color-neutral-foreground2-rest);line-height:1.45"
        >
          A realistic reset flow usually combines the current password, a new password, and short
          policy guidance in one contained surface.
        </div>
      </div>

      <ui-password
        label="Current password"
        placeholder="Enter current password"
        autocomplete="current-password"
        formControlName="currentPassword"
      />

      <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem">
        <ui-password
          label="New password"
          placeholder="Create new password"
          autocomplete="new-password"
          formControlName="newPassword"
          helpText="Use at least 8 characters and avoid reusing the current password."
        />

        <ui-password
          label="Confirm password"
          placeholder="Repeat new password"
          autocomplete="new-password"
          formControlName="confirmPassword"
          [errorText]="confirmError"
          [helpText]="confirmHelpText"
        />
      </div>

      <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" [disabled]="resetForm.invalid || !!confirmError">
          Update password
        </ui-button>
        <ui-button
          type="button"
          variant="secondary"
          appearance="outline"
          (click)="resetForm.reset(defaults)"
        >
          Reset values
        </ui-button>
      </div>
    </form>
  `,
})
export class PasswordResetPanelDemoComponent {
  protected readonly defaults = {
    currentPassword: '',
    newPassword: '',
    confirmPassword: '',
  };

  protected readonly resetForm = new FormGroup({
    currentPassword: new FormControl(this.defaults.currentPassword, {
      nonNullable: true,
      validators: [Validators.required],
    }),
    newPassword: new FormControl(this.defaults.newPassword, {
      nonNullable: true,
      validators: [Validators.required, Validators.minLength(8)],
    }),
    confirmPassword: new FormControl(this.defaults.confirmPassword, {
      nonNullable: true,
      validators: [Validators.required],
    }),
  });

  protected get confirmError(): string {
    const confirmValue = this.resetForm.controls.confirmPassword.value;
    if (!confirmValue) {
      return '';
    }
    return confirmValue === this.resetForm.controls.newPassword.value
      ? ''
      : 'Passwords do not match.';
  }

  protected get confirmHelpText(): string {
    const confirmValue = this.resetForm.controls.confirmPassword.value;
    if (!confirmValue) {
      return 'Repeat the new password.';
    }
    return confirmValue === this.resetForm.controls.newPassword.value
      ? 'Ready to update.'
      : 'Use the same value as the new password field.';
  }
}
```

## Accessibility

### Label and name
Prefer a visible `label` so the purpose of the secret is explicit. Help and error text contribute through `aria-describedby`, and `ariaLabel` can be used when no visible label is appropriate.

### Keyboard and field actions
This is a standard text-entry field backed by a native password input. Reveal and clear actions are exposed as separate buttons only when the field is editable.

| Aspect | Behavior |
| --- | --- |
| focus | native password input receives focus |
| typing | native password input behavior |
| reveal action | toggles the input type between `password` and `text` |
| clear action | appears only when the field has a value and is editable |
| readonly / disabled | actions are hidden and direct editing is blocked |

### Autocomplete semantics
Use `autocomplete="current-password"` for sign-in or identity verification and `autocomplete="new-password"` for creation or reset flows. This improves browser autofill and password-manager behavior without changing field layout.
