Skip to main content
View Zag.js on Github
Join the Discord server

Password Input

Properties

Features

  • Includes button to toggle visibility of the password
  • Automatic focus restoration to the input
  • Resets visibility to hidden after form submission
  • Ignore password management apps like 1Password, LastPass, etc.

Installation

To use the password-input machine in your project, run the following command in your command line:

npm install @zag-js/password-input @zag-js/react # or yarn add @zag-js/password-input @zag-js/react

Anatomy

To set up the password-input correctly, you'll need to understand its anatomy and how we name its parts.

Each part includes a data-part attribute to help identify them in the DOM.

Usage

First, import the password-input package into your project

import * as passwordInput from "@zag-js/password-input"

The password-input package exports two key functions:

  • machine — The state machine logic for the password-input widget.
  • connect — The function that translates the machine's state to JSX attributes and event handlers.

You'll also need to provide a unique id to the useMachine hook. This is used to ensure that every part has a unique identifier.

Next, import the required hooks and functions for your framework and use the password-input machine in your project 🔥

import * as passwordInput from "@zag-js/password-input" import { useMachine, normalizeProps } from "@zag-js/react" import { EyeIcon, EyeOffIcon } from "lucide-react" import { useId } from "react" function PasswordInput() { const service = useMachine(passwordInput.machine({ id: useId() })) const api = passwordInput.connect(service, normalizeProps) return ( <div {...api.getRootProps()}> <label {...api.getLabelProps()}>Password</label> <div {...api.getControlProps()}> <input {...api.getInputProps()} /> <button {...api.getVisibilityTriggerProps()}> <span {...api.getIndicatorProps()}> {api.visible ? <EyeIcon /> : <EyeOffIcon />} </span> </button> </div> </div> ) }

Setting the initial visibility

Use the defaultVisible context property to set the initial visibility of the password input.

const service = useMachine( passwordInput.machine({ id: useId(), defaultVisible: true, }), )

Controlling the visibility

Use the visible and onVisibilityChange context properties to control the visibility of the password input.

The onVisibilityChange callback is invoked when the visibility changes.

const service = useMachine( passwordInput.machine({ id: useId(), visible: true, onVisibilityChange(details) { console.log(details) }, }), )

Ignoring password managers

Set the ignorePasswordManager context property to true to ignore password managers like 1Password, LastPass, etc.

This is useful when you want to ensure that the password input is not managed by password managers. Currently, this only works for 1Password, LastPass, Bitwarden, Dashlane, and Proton Pass.

const service = useMachine( passwordInput.machine({ id: useId(), ignorePasswordManager: true, }), )

Managing autocompletion

Configure the autoComplete context property to manage autocompletion.

  • new-password — The user is creating a new password.
  • current-password — The user is entering an existing password.
const service = useMachine( passwordInput.machine({ id: useId(), autoComplete: "new-password", }), )

Making the input required

Set the required context property to true to make the input required.

const service = useMachine( passwordInput.machine({ id: useId(), required: true, }), )

Making the input read only

Set the readOnly context property to true to make the input read only.

const service = useMachine( passwordInput.machine({ id: useId(), readOnly: true, }), )

Styling guide

Earlier, we mentioned that each password-input part has a data-part attribute added to them to select and style them in the DOM.

[data-scope="password-input"][data-part="root"] { /* styles for the root part */ } [data-scope="password-input"][data-part="input"] { /* styles for the input part */ } [data-scope="password-input"][data-part="visibility-trigger"] { /* styles for the visibility trigger part */ } [data-scope="password-input"][data-part="indicator"] { /* styles for the indicator part */ } [data-scope="password-input"][data-part="control"] { /* styles for the control part */ } [data-scope="password-input"][data-part="label"] { /* styles for the label part */ }

Visibility State

Use the [data-state="visible"] and [data-state="hidden"] attributes to style the password input when it is visible or hidden.

[data-scope="password-input"][data-part="input"][data-state="visible"] { /* styles for the visible state (for input) */ } [data-scope="password-input"][data-part="visibility-trigger"][data-state="visible"] { /* styles for the visible state (for visibility trigger) */ }

Disabled State

Use the [data-disabled] attribute to style the password input when it is disabled.

[data-scope="password-input"][data-part="input"][data-disabled] { /* styles for the disabled state */ }

Invalid State

Use the [data-invalid] attribute to style the password input when it is invalid.

[data-scope="password-input"][data-part="input"][data-invalid] { /* styles for the invalid state */ }

Readonly State

Use the [data-readonly] attribute to style the password input when it is read only.

[data-scope="password-input"][data-part="input"][data-readonly] { /* styles for the readonly state */ }

Methods and Properties

Machine Context

The password-input machine exposes the following context properties:

  • defaultVisiblebooleanThe default visibility of the password input.
  • visiblebooleanWhether the password input is visible.
  • onVisibilityChange(details: VisibilityChangeDetails) => voidFunction called when the visibility changes.
  • idsPartial<{ input: string; visibilityTrigger: string; }>The ids of the password input parts
  • disabledbooleanWhether the password input is disabled.
  • invalidbooleanThe invalid state of the password input.
  • readOnlybooleanWhether the password input is read only.
  • requiredbooleanWhether the password input is required.
  • translationsPartial<{ visibilityTrigger: (visible: boolean) => string; }>The localized messages to use.
  • ignorePasswordManagersbooleanWhen `true`, the input will ignore password managers. **Only works for the following password managers** - 1Password, LastPass, Bitwarden, Dashlane, Proton Pass
  • autoComplete"current-password" | "new-password"The autocomplete attribute for the password input.
  • namestringThe name of the password input.
  • dir"ltr" | "rtl"The document's text/writing direction.
  • idstringThe unique identifier of the machine.
  • getRootNode() => ShadowRoot | Node | DocumentA root node to correctly resolve document in custom environments. E.x.: Iframes, Electron.

Machine API

The password-input api exposes the following methods:

  • visiblebooleanWhether the password input is visible.
  • disabledbooleanWhether the password input is disabled.
  • invalidbooleanWhether the password input is invalid.
  • focus() => voidFocus the password input.
  • setVisible(value: boolean) => voidSet the visibility of the password input.

Edit this page on GitHub

Proudly made in🇳🇬by Segun Adebayo

Copyright © 2025
On this page