---
id: "packages/active-ui/password-input"
title: "PasswordInput"
description: "A password field with a button that shows the password, and an indicator of the rules a new password meets."
url: "/packages/active-ui/password-input"
locale: "en"
revision: "9b20fa41dbd6750b"
---

# PasswordInput

`PasswordInput` is a password field with a button to show and hide what was typed.
`PasswordStrengthIndicator` shows how far a new password meets the rules your application sets.
Use them together for a new password, or the field alone to sign in.

**Example: A new password and its rules**

Client: Runs entirely in your browser. Source: `examples/ui/password-input.tsx`.

```tsx
// apps/docs/examples/ui/password-input.tsx
'use client';

import {useState} from 'react';

import {PasswordInput} from '@workspace/active-ui/components/composed/password-input';
import {PasswordStrengthIndicator} from '@workspace/active-ui/components/composed/password-strength-indicator';
import {
  Field,
  FieldLabel,
} from '@workspace/active-ui/components/primitives/field';

// The rules are the application's: the indicator only shows them.
function criteriaFor(password: string) {
  return [
    {id: 'length', label: 'At least 12 characters', met: password.length >= 12},
    {id: 'digit', label: 'A digit', met: /\d/.test(password)},
    {
      id: 'case',
      label: 'An upper-case and a lower-case letter',
      met: /[a-z]/.test(password) && /[A-Z]/.test(password),
    },
  ];
}

/**
 * A new password with a button to show it, and the rules it has to meet.
 * Type to see the bar and the rules change; when every rule is met, one
 * confirmation replaces the list.
 */
export default function PasswordInputExample() {
  const [password, setPassword] = useState('');
  return (
    <Field className="w-full max-w-sm">
      <FieldLabel htmlFor="new-password">New password</FieldLabel>
      <PasswordInput
        id="new-password"
        autoComplete="new-password"
        value={password}
        onChange={(event) => setPassword(event.target.value)}
        ariaLabelShowPassword="Show password"
        ariaLabelHidePassword="Hide password"
        aria-describedby="new-password-rules"
      />
      <PasswordStrengthIndicator
        id="new-password-rules"
        criteria={criteriaFor(password)}
        compliantLabel="The password meets every rule."
        criterionMetLabel="met"
        criterionUnmetLabel="not met"
      />
    </Field>
  );
}
```

## What the composition adds

- **A reveal button that is a real tab stop**, named after the action it offers: "Show password"
  while hidden, "Hide password" while shown.
- **The same field throughout.** Showing switches `type` on the same input, so the value, the cursor,
  `name`, `id` and `autoComplete` stay, and password managers see one field.
- **No password-manager blocking.** The field adds no `autoComplete="off"` or ignore attributes;
  you declare the role with `autoComplete` (`current-password`, `new-password`).
- **`disabled` covers the button too**; `readOnly` leaves the button working, so the value can
  still be read.
- **Rules as presentation.** The indicator receives a list of translated rules with `met` for each,
  shows a bar and the open rules, and one confirmation once all are met. It validates nothing.

## Usage

```tsx
import {PasswordInput} from '@workspace/active-ui/components/composed/password-input';
import {PasswordStrengthIndicator} from '@workspace/active-ui/components/composed/password-strength-indicator';

<PasswordInput
  id="new-password"
  autoComplete="new-password"
  value={password}
  onChange={(event) => setPassword(event.target.value)}
  ariaLabelShowPassword="Show password"
  ariaLabelHidePassword="Hide password"
/>
<PasswordStrengthIndicator
  criteria={[{id: 'length', label: 'At least 12 characters', met: password.length >= 12}]}
  compliantLabel="The password meets every rule."
  criterionMetLabel="met"
  criterionUnmetLabel="not met"
/>
```

## What your application provides

- The rules and the check of each one, and the validation on submit: the indicator only shows.
- Both translated button names, and the state words `met` and `not met` for screen readers.
- `autoComplete`, and for a secret that is not a sign-in credential, the attributes that tell
  password managers to skip it.

## Accessibility and keyboard

- `Tab` moves from the field to the reveal button; `Enter` or `Space` toggles it.
- The bar and the icons are hidden from assistive technology; each rule carries its state as
  hidden text, so it is not shown by colour and shape alone.
- The indicator is not a live region: it would talk on every keystroke. Link it to the field with
  `aria-describedby`, as in the example, so it is read with the field.

## API

### PasswordInput

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `ariaLabelHidePassword` | `string` | yes | Accessible name of the button while the password is visible. |
| `ariaLabelShowPassword` | `string` | yes | Accessible name of the button **while the password is hidden**: the action the button then offers.  Supplied translated and required; `active-ui` does not translate. An optional prop with an English default is not an i18n-agnostic API: it produces silent English text on every screen where the caller forgets it, and that text turns no check red. Same rule as `openCalendarLabel` on `DateField`. |
| `ref` | `Ref<HTMLInputElement>` | no | Allows getting a ref to the component instance. Once the component unmounts, React will set `ref.current` to `null` (or call the ref with `null` if you passed a callback ref). |

**PasswordInputProps**

```ts
interface PasswordInputProps extends React.ComponentProps<'input'> {
  ariaLabelShowPassword: string;
  ariaLabelHidePassword: string;
}
```

### PasswordStrengthIndicator

**PasswordStrengthIndicator**

| Prop | Type | Required | Description |
| --- | --- | --- | --- |
| `compliantLabel` | `string` | yes | The translated text that appears as soon as all requirements are met. |
| `criteria` | `readonly PasswordStrengthCriterion[]` | yes | The requirements, in the order in which they are shown. An empty list means: nothing to show, and then this component renders nothing. |
| `criterionMetLabel` | `string` | yes | Translated state text for a met requirement, for example "Met".  Required, and visible only to assistive technology: the met/unmet distinction is visually in the icon shape, and that is `aria-hidden`. Without this text a screen reader hears the requirement but not the state. |
| `criterionUnmetLabel` | `string` | yes | Translated state text for an open requirement, for example "Not met". |

**PasswordStrengthCriterion**

```ts
interface PasswordStrengthCriterion {
  id: string;
  label: string;
  met: boolean;
}
```

One requirement a password must meet, in the form in which this component
shows it.

This is **presentation, not policy**. `active-ui` does not know that
something like a minimum length exists, knows no password rules and
validates nothing; it receives a list of translated rules with a check mark
each.

**PasswordStrengthIndicatorProps**

```ts
interface PasswordStrengthIndicatorProps extends Omit<
  React.ComponentProps<'div'>,
  'children'
> {
  criteria: readonly PasswordStrengthCriterion[];
  compliantLabel: string;
  criterionMetLabel: string;
  criterionUnmetLabel: string;
}
```
