Skip to content

Fields

Password Field

A hidden-first password input with a built-in show and hide action.

When to use it: Use it for sign-in, account creation, and password changes where people may need to inspect what they entered.

On this page

Example

Sign in

Enter the password for ada@example.com.

You can paste a password or use your password manager.
Password Field.tsxtsx
import { useState } from "react";
import {
  Description,
  FieldError,
  Label,
  PasswordField,
  PasswordFieldInput,
  PasswordFieldToggle,
} from "@comp0/react";
import { EyeIcon, EyeSlashIcon } from "@heroicons/react/16/solid";

export function Example() {
  const [hasValidationError, setHasValidationError] = useState(false);
  const [signedIn, setSignedIn] = useState(false);

  return (
    <form
      className="flex max-w-sm flex-col gap-5 rounded-xl border border-zinc-950/10 bg-white p-5 shadow-sm dark:border-white/10 dark:bg-zinc-900"
      onSubmit={(event) => {
        event.preventDefault();
        setSignedIn(true);
      }}
    >
      <div>
        <h2 className="text-lg font-semibold text-zinc-950 dark:text-zinc-50">Sign in</h2>
        <p className="mt-1 text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
          Enter the password for ada@example.com.
        </p>
      </div>
      <PasswordField
        as="div"
        className="flex flex-col gap-1.5"
        invalid={hasValidationError}
        onChange={() => setHasValidationError(false)}
        required
      >
        <Label className="text-base font-medium text-zinc-900 sm:text-sm dark:text-zinc-100">
          Password
        </Label>
        <div className="relative">
          <PasswordFieldInput
            autoComplete="current-password"
            className="w-full rounded border border-zinc-950/10 bg-white px-3 py-2.5 pr-24 text-base text-zinc-950 outline-teal-600 focus-visible:outline-2 sm:py-2 sm:text-sm dark:border-white/10 dark:bg-zinc-950 dark:text-zinc-50 dark:outline-teal-400"
            name="password"
            onInvalid={() => setHasValidationError(true)}
          />
          <PasswordFieldToggle className="absolute top-1/2 right-1 flex h-8 -translate-y-1/2 items-center justify-center gap-1.5 rounded px-2 text-sm font-medium text-zinc-500 outline-teal-600 hover:bg-zinc-100 hover:text-zinc-800 focus-visible:outline-2 dark:text-zinc-400 dark:outline-teal-400 dark:hover:bg-zinc-800 dark:hover:text-zinc-100">
            {({ passwordVisible }) => {
              if (passwordVisible) {
                return (
                  <>
                    <EyeSlashIcon className="size-4" aria-hidden="true" />
                    Hide
                  </>
                );
              }
              return (
                <>
                  <EyeIcon className="size-4" aria-hidden="true" />
                  Show
                </>
              );
            }}
          </PasswordFieldToggle>
        </div>
        <Description className="text-base text-zinc-600 sm:text-sm dark:text-zinc-400">
          You can paste a password or use your password manager.
        </Description>
        <FieldError className="text-base text-red-600 sm:text-sm dark:text-red-400">
          Enter your password to sign in.
        </FieldError>
      </PasswordField>
      <button
        className="rounded bg-teal-600 px-3 py-2.5 text-base font-medium text-white outline-teal-600 hover:bg-teal-700 focus-visible:outline-2 focus-visible:outline-offset-2 sm:py-2 sm:text-sm dark:bg-teal-500 dark:hover:bg-teal-400"
        type="submit"
      >
        Sign in
      </button>
      {signedIn && (
        <p className="text-base text-emerald-700 sm:text-sm dark:text-emerald-400" role="status">
          Signed in.
        </p>
      )}
    </form>
  );
}

Anatomy

Dashed frames are invisible state providers; shaded shapes own real DOM. Numbered pins match the list below.

A wireframe sketch of the assembled component. Each numbered marker matches a part in the list that follows.

  1. PasswordField

    Field provider with an internal hidden-first reveal state; it owns no DOM unless as is supplied. Does not add a DOM element.

  2. Label

    Native label linked to the password input. Owns a DOM element.

  3. PasswordFieldInput

    Native password input that becomes text only while the field is revealed. Owns a DOM element.

  4. PasswordFieldToggle

    Client-only native button that reveals or re-hides the same input; its name changes between Show password and Hide password. Owns a DOM element.

  5. Description / FieldErrorOptional

    Linked help or error text. Owns a DOM element.

Step by step

  1. 1

    Add the main part

    Start PasswordField with a Label and PasswordFieldInput.

  2. 2

    Add the supporting parts

    Add PasswordFieldToggle plus Description and FieldError when people need help or validation feedback.

  3. 3

    Make the behavior clear

    Choose current-password for sign-in or new-password for a new credential; the field starts hidden and manages revealing itself.

    Exampletsx
    <PasswordField required><Label>Password</Label><PasswordFieldInput name="password" autoComplete="current-password" /><PasswordFieldToggle /><Description>Use a password manager if you have one.</Description><FieldError>Enter your password.</FieldError></PasswordField>

Keyboard

Moves from the password input to the reveal button.
Space
Shows or hides the password from the reveal button.
Submits the surrounding form from the password input.

Forms and accessibility

PasswordFieldInput submits its native name and password value. It re-hides after the owning form submits and when a page is restored from the back-forward cache.

Accessibility checklist

  • PasswordField is progressively enhanced: without JavaScript, the native password input still works; the reveal button appears only after hydration.
  • Use autoComplete="current-password" for sign-in and autoComplete="new-password" for a new credential. Keep paste and password-manager filling available; PasswordFieldInput defaults to spellCheck={false} and autoCapitalize="none".
  • The changing Show password and Hide password name describes the action, so the toggle does not use aria-pressed. Avoid confirm-password fields and maxLength: let people inspect or paste the credential, then show a clear validation error if needed.

API reference

Importtsx
import { Description, FieldError, Label, PasswordField, PasswordFieldInput, PasswordFieldToggle } from "@comp0/react";

PasswordField

Context only

Field provider with an internal hidden-first reveal state; it owns no DOM unless as is supplied.

PropTypeDescription
valuestringControlled password value.
defaultValuestringInitial password value.
onChange(value: string) => voidReceives the next password value.
disabled / invalid / requiredbooleanField-wide states shared with every part.
visibleAnnouncement / hiddenAnnouncementstringLocalizes the polite status announced after the reveal state changes.

Label

DOM element

Native label linked to the password input.

PropTypeDescription
htmlForstringAuto-wired to the field control; set it only to override.

PasswordFieldInput

DOM element

Native password input that becomes text only while the field is revealed.

PropTypeDescription
namestringSubmission name for the password.
autoComplete"current-password" | "new-password"Password-manager hint chosen for this form.
spellCheckbooleanDefaults to false to keep password text out of spell checking.
autoCapitalizestringDefaults to "none", including while the password is revealed as text.

PasswordFieldToggle

DOM element

Client-only native button that reveals or re-hides the same input; its name changes between Show password and Hide password.

PropTypeDescription
children({ passwordVisible }) => ReactNodeOptional visible content based on the current visibility; defaults to the current action label.
showLabel / hideLabelstringLocalizes the changing accessible and default visible action labels.
disabledbooleanOverrides the field-wide disabled state for this button.

Description / FieldError

OptionalDOM element

Linked help or error text.

PropTypeDescription
forceMountbooleanFieldError only: keep it rendered while the field is valid.

Style hooks

Attributes that appear while a state is true. Target them with Tailwind data variants such as data-open:bg-zinc-100, or with any CSS selector.

[data-visible]

on PasswordField wrapper, PasswordFieldInput, PasswordFieldToggle

The password is revealed.
[data-invalid]

on PasswordFieldInput

The field is invalid.
[data-disabled]

on PasswordFieldInput, PasswordFieldToggle

The field is disabled.

Keep exploring