Skip to content
cennge-ui
GitHubv0.3.1, changelog

PasswordInput

A password field with a button to show what you typed and a hint when Caps Lock is on.

5 more characters, at least 12 in all
  1. The eye shows the password; the caret stays where it was, so you can keep typing.
  2. Show it, then press Sign in: submitting the form hides it again.
  3. Type with Caps Lock on: a hint appears under the field until it goes off or you leave.
Live: the component itself, not a picture of it.

Field marks

Import
import { PasswordInput } from "cennge-ui";
Size
3.7 KB gzip for this import, its dependencies aside
Pattern
Native <input type="password"> and a toggle button with aria-pressed
Keyboard
SpaceEnter
State
Value and visibility, each controlled or uncontrolled
SSR
Rendered on the server in the Next.js check; hydrates without a warning
Autofill
current-password by default; new-password on sign-up
Hidden again
When its form is submitted or reset
Tests
Unit tests; end-to-end in Chromium, Firefox and WebKit, on desktop and phone viewports: password-input

When to use#

Use a PasswordInput wherever a password is typed: sign-in, sign-up, a change of password. Showing the password lets people check a long one before they send it; the caret stays where it was when it switches, and the field goes back to dots as soon as the form is sent.

Set autoComplete="new-password" on sign-up and change-password forms, so password managers offer to generate one; the default, current-password, is for signing in. Give the email or username field in the same form autoComplete="username", so the manager knows which account the password belongs to.

Similar#

  • Input is the plain text field; it has no show/hide button and no Caps Lock hint.
  • OtpInput is for one-time codes from an authenticator app, an email or a text message.

Sign-up form#

Inside a Form, the browser's own checks (isRequired, minLength) show their message under the field. Press Create account with a short password.

At least 12 characters
sign-up.tsx
import { Button, Form, Input, PasswordInput, toast } from "cennge-ui";

export default function SignUpForm() {
  return (
    <Form
      className="flex w-full max-w-80 flex-col gap-4"
      onSubmit={(event) => {
        event.preventDefault();
        toast.success("Account created", { description: String(new FormData(event.currentTarget).get("email")) });
      }}
    >
      <Input label="Email" name="email" type="email" autoComplete="username" placeholder="dev@example.com" isRequired />
      <PasswordInput
        label="Password"
        name="password"
        autoComplete="new-password"
        minLength={12}
        isRequired
        description="At least 12 characters"
      />
      <Button type="submit" color="primary" className="self-start">
        Create account
      </Button>
    </Form>
  );
}

One switch for both fields#

isVisible and onVisibilityChange control the visibility from outside. Here one Switch and either eye show or hide both fields together.

shared-visibility.tsx
import { useState } from "react";
import { PasswordInput, Switch } from "cennge-ui";

export default function ChangePassword() {
  const [isVisible, setVisible] = useState(false);
  const [password, setPassword] = useState("");
  const [confirmation, setConfirmation] = useState("");
  const isMismatch = confirmation.length > 0 && confirmation !== password;

  return (
    <div className="flex w-full max-w-80 flex-col gap-4">
      <PasswordInput
        label="New password"
        autoComplete="new-password"
        value={password}
        onValueChange={setPassword}
        isVisible={isVisible}
        onVisibilityChange={setVisible}
      />
      <PasswordInput
        label="Repeat it"
        autoComplete="new-password"
        value={confirmation}
        onValueChange={setConfirmation}
        isVisible={isVisible}
        onVisibilityChange={setVisible}
        isInvalid={isMismatch}
        errorMessage="The two passwords differ"
      />
      <Switch size="sm" isSelected={isVisible} onValueChange={setVisible}>
        Show passwords
      </Switch>
    </div>
  );
}

Accessibility#

The eye is a button named "Show password" whatever the state; its aria-pressed says whether the password is shown, and aria-controls points at the field. It is in the Tab order after the field and works with Space and Enter.

The Caps Lock hint joins the field's aria-describedby, before the description, so it is read with the field. A browser only tells the state of Caps Lock in a key event, so the hint appears with the first key pressed in the field, not on focus. Translate the button with toggleLabel and the hint with capsLockWarning, or turn the hint off with capsLockWarning={false}.

Styling#

It shares the Input's box: variant, color, size, radius and startContent; the end of the box belongs to the eye. classNames reaches base, label, inputWrapper, input, toggle, capsLock, description and errorMessage.

Props#

PropTypeDefault
label
React.ReactNode
–
description
React.ReactNode
–
errorMessage
React.ReactNodeShown instead of description while isInvalid.
–
value
string
–
defaultValue
string
–
onValueChange
(value: string) => void
–
autoComplete
"current-password""new-password""new-password" on sign-up and change-password forms, so password managers offer to generate one.
"current-password"
isVisible
booleanShow the password as plain text. A form submit or reset hides it again.
–
defaultVisible
boolean
–
onVisibilityChange
(isVisible: boolean) => void
–
toggleLabel
stringAccessible name of the show/hide button. It stays the same; the button's pressed state says whether the password is shown.
"Show password"
capsLockWarning
React.ReactNodeHint shown while Caps Lock is on. false turns it off.
"Caps Lock is on"
isInvalid
boolean
–
isRequired
boolean
–
isDisabled
boolean
–
variant
"bordered""flat""faded""underlined"
"flat"
color
"default""primary""secondary""success""warning""danger""info"Focus colour.
"primary"
size
"sm""md""lg"
"md"
radius
"none""sm""md""lg""full"
"md"
startContent
React.ReactNode
–
classNames
Partial<Record<PasswordInputSlots, string>>
–

Also takes every attribute of <input>, except size, color, type, value, defaultValue, autoComplete, which mean something else here.