# Password field

A text field for a password or a passphrase, with a button at its end that shows and hides what is typed.

Block: `smbk-password-field`. Status: experimental. Figma: the Figma file, https://www.figma.com/community/file/1688324308358870630. Desktop and mobile: differ by presentation only.

## Options

| Axis | Values | Default | Meaning |
|---|---|---|---|
| `size` | `md`, `sm` | `md` | The input’s two heights, with its padding and text. The button’s eye is 16 px at both; at sm the button is a 24 px square, so it fits inside the small well. Small text never goes under 16 px on a phone. |
| `error` | on / off | off | The password is wrong or breaks a rule. Draws the danger border, kept while focused, and the error icon before the button. |

Parts: `smbk-password-field__control`, `smbk-password-field__toggle`

## Markup

```html
<span class="smbk-input smbk-input--size-md smbk-password-field smbk-password-field--size-md">
  <input
    id="passwordpassword-field-1"
    type="password"
    class="smbk-input__control smbk-password-field__control"
    autoComplete="current-password"
    autoCapitalize="off"
    autoCorrect="off"
    spellCheck="false"
    aria-label="Password"
    value="correct-horse-battery"
  >
  <span class="smbk-input__trailing-action">
    <button
      type="button"
      class="smbk-btn smbk-btn--tone-ghost smbk-btn--size-sm smbk-btn--icon-only smbk-password-field__toggle"
      aria-label="Show password"
      aria-controls="passwordpassword-field-1"
    >
      <i class="ph ph-eye smbk-icon smbk-icon--size-md smbk-btn__icon" aria-hidden="true"></i>
    </button>
  </span>
</span>
```

## React

```tsx
import { PasswordField } from './design-system/components/password-field/password-field.js';

<PasswordField size="md" defaultValue="correct-horse-battery" aria-label="Password" />
```

## Stylesheet

```css
/* smbk-password-field — Password field. Figma "Password input" 7106:682.
 * Built on the input: the block always sits on an smbk-input well, the native
 * control is the input's control part, and the show and hide button is a ghost
 * icon button in the input's trailing action. The padding, the text, hover,
 * focus, error, disabled and the two sizes are the input's own, so a change to
 * the input reaches the password field. This stylesheet adds only what the
 * button needs. */

/* Some browsers draw a reveal button of their own inside a password control; the field has its own, so
   there is one, in the same place, in every browser. */
.smbk-password-field__control::-ms-reveal,
.smbk-password-field__control::-ms-clear {
  display: none;
}

/* Small: Figma puts the 32 px button in the 32 px well, which would cover the well's edge. The button here
   is the 24 px square, with the 16 px eye Figma draws, and the margin gives back the rest of Figma's 32 px
   place, so the eye sits where Figma draws it. Two classes on the icon, so it wins over the button's own
   small icon whichever stylesheet loads first. */
.smbk-password-field__toggle.smbk-btn--size-xs {
  margin-inline: calc((var(--smbk-size-control-sm) - var(--smbk-size-control-xs)) / 2);
}

.smbk-password-field__toggle.smbk-btn--size-xs .smbk-btn__icon {
  font-size: var(--smbk-size-icon-sm);
}

/* ---- touch: the small toggle stops halfway to the value ----
   The toggle takes an invisible press area on a touch screen; toward the value it reaches only halfway into the gap,
   which in the small field is the well's gap and the margin that gives back the rest of the small control's place.
   Nothing drawn moves. */

@media (pointer: coarse) {
  .smbk-input--size-sm > .smbk-input__control + .smbk-input__trailing-action > .smbk-password-field__toggle.smbk-btn--size-xs::after {
    inset-inline-start: max(min(0%, (100% - var(--smbk-size-target-comfortable)) / 2), (var(--smbk-space-inline-sm) + (var(--smbk-size-control-sm) - var(--smbk-size-control-xs)) / 2) / -2);
  }
}
```

## Tokens it reads

```json
{
  "size": {
    "control": {
      "sm": {
        "$type": "dimension",
        "$value": "{{size.32}}",
        "$description": "Height of a small control: 32 comfortable, 28 compact. Dashboard recipe: use compact density; 40 for the page’s one main action and for forms; 32 for toolbars and filters, the size used most; 28 for actions inside table rows and cards. On phones switch to comfortable density, or give small controls an invisible 44 px tap area (size/target/comfortable)."
      },
      "xs": {
        "$type": "dimension",
        "$value": "{{size.24}}",
        "$description": "Height of the extra-small control: 24 in both densities, the smallest target allowed. Dashboard recipe: use compact density; 40 for the page’s one main action and for forms; 32 for toolbars and filters, the size used most; 28 for actions inside table rows and cards. On phones switch to comfortable density, or give small controls an invisible 44 px tap area (size/target/comfortable)."
      }
    },
    "icon": {
      "sm": {
        "$type": "dimension",
        "$value": "{{size.16}}",
        "$description": "Icon box, small."
      }
    },
    "target": {
      "comfortable": {
        "$type": "dimension",
        "$value": "{{size.44}}",
        "$description": "Comfortable touch target (44)."
      }
    }
  },
  "space": {
    "inline": {
      "sm": {
        "$type": "dimension",
        "$value": "{{space.6}}",
        "$description": "Gap between things side by side, small."
      }
    }
  }
}
```

## Purpose

A text field for a password or a passphrase. It hides what is typed and has a button at its end that shows it, so the reader can check a long password before sending it instead of typing it again. Everything else is the input's: the well, the sizes, the states and the error look.

## Anatomy

- The block, always on the input's well: its markup carries the input's classes as well as its own.
- The control part, a native password control, which is also the input's control part. It shows dots while the password is hidden and the words while it is shown.
- In error, the input's error icon, a warning sign before the button.
- The toggle part, a ghost icon button in the input's trailing action: an eye while the password is hidden, an eye with a line through it while it is shown. At the medium size it is the small icon button; at the small size it is the extra-small square, with the same 16 px eye, so it fits inside the small well.

## When to use

- Signing in, and choosing or changing a password.
- Any secret the reader types and may want to check: a passphrase, a recovery code.

## When not to use

- A code the reader copies from a message and never needs to hide, such as a one-time code. Use the [input](input.md).
- A key or a token the page shows for copying. Use the input, read-only, with a copy button in its trailing action.

## Behavior

The password starts hidden. Pressing the button shows it as plain text and turns the eye into a crossed-out eye; pressing it again hides it. Nothing else changes: the value stays, the field keeps its size, and the reader keeps typing where they were. Pressed with a mouse while typing, the focus stays in the field; reached with Tab and pressed with Enter or Space, the focus stays on the button. Sending the form hides the password again first, so the browser never keeps it as plain text.

The wrapper holds its own state, or follows the state the page gives it and reports each press. A long password scrolls inside the field and never widens it.

The control asks the browser's password manager for the saved password unless given another autocomplete: a form that creates a password passes `new-password`, so the manager offers a strong one. Pasting is always allowed, and the control never corrects, capitalizes or checks the spelling of what is typed.

The field can say when Caps Lock is on: it reports Caps Lock each time a key is pressed in it, and reports it off when the field loses focus. The page shows the notice as the field's warning, under the help text.

A disabled field disables its button too. A read-only field keeps the button, so the value can still be read.

## Accessibility

### What it does for you

- In development, a password field with no name logs a warning in the console.
- The button says what it will do: "Show password" while the password is hidden, "Hide password" while it shows. Its name changes rather than a pressed state, so a screen reader hears the action, not a state to work out.
- The button comes after the field in the Tab order and draws the system's focus ring.
- A screen reader hears the field as a secure text field while the password is hidden and as a text field while it shows.
- A Caps Lock notice shown as the field's warning is read out when it appears, without cutting in.
- Pressed with a mouse while typing, the button leaves the focus in the field; reached with Tab and pressed, the focus stays on the button.

### What you must do

- Give it a label like any input; inside a field it has one.
- Pass `showLabel` and `hideLabel` for another language or for "Show passphrase".
- Write an error that says what to put right, without saying whether the name or the password was the wrong one.

### How to test

- Tab to the field, then Tab again: the button takes focus and shows the focus ring. Press Enter, then Space: the password shows, then hides, and focus stays on the button.
- With a screen reader, the hidden field is read as a secure text field, and the button as "Show password" or "Hide password", whichever it will do.
- Turn Caps Lock on while typing: the notice is read out when it appears.
- With text at 200% and the page 320 pixels wide, a long password scrolls inside the field and the button stays beside it.
- In a forced-color mode, the field's focus border and the button's focus ring stay visible.

### Keyboard

| Key | What it does |
|---|---|
| Tab | Moves focus to the field, then to the show and hide button. |
| Enter or Space | On the button, shows or hides the password. |

## Usage rules

### Do

- Put the password's rules in the field's help text, so they are known before the first try.
- Pass `new-password` when the form creates a password.

### Don't

- Block pasting into the field: it stops password managers and long, safe passwords.
- Ask the reader to type a new password twice when the field can show it.
