Password Input
A component that allows users to enter secure text like (passwords and api keys)
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-partattribute to help identify them in the DOM.
Examples
Learn how to use the PasswordInput component in your project. Let's take a look at the most basic example:
import { PasswordInput } from '@ark-ui/react/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-react'
export const Basic = () => (
<PasswordInput.Root>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
import { PasswordInput } from '@ark-ui/solid/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-solid'
export const Basic = () => (
<PasswordInput.Root>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
<script setup lang="ts">
import { PasswordInput } from '@ark-ui/vue/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-vue-next'
</script>
<template>
<PasswordInput.Root>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input placeholder="Enter your password" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator>
<EyeIcon />
<template #fallback>
<EyeOffIcon />
</template>
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
</template>
Autocomplete
Use the autoComplete prop to manage autocompletion in the input.
new-password— The user is creating a new password.current-password— The user is entering an existing password.
import { PasswordInput } from '@ark-ui/react/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-react'
export const Autocomplete = () => (
<PasswordInput.Root autoComplete="new-password">
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
import { PasswordInput } from '@ark-ui/solid/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-solid'
export const Autocomplete = () => (
<PasswordInput.Root autoComplete="new-password">
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
<script setup lang="ts">
import { PasswordInput } from '@ark-ui/vue/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-vue-next'
</script>
<template>
<PasswordInput.Root autoComplete="new-password">
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input placeholder="Enter your password" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator>
<EyeIcon />
<template #fallback>
<EyeOffIcon />
</template>
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
</template>
Root Provider
Use the usePasswordInput hook to create the password input store and pass it to the PasswordInput.RootProvider
component. This allows you to have maximum control over the password input programmatically.
import { PasswordInput, usePasswordInput } from '@ark-ui/react/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-react'
export const RootProvider = () => {
const passwordInput = usePasswordInput()
return (
<>
<button onClick={() => passwordInput.focus()}>Focus</button>
<button onClick={() => passwordInput.setVisible(!passwordInput.visible)}>
{passwordInput.visible ? 'Hide' : 'Show'} Password
</button>
<PasswordInput.RootProvider value={passwordInput}>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.RootProvider>
</>
)
}
import { PasswordInput, usePasswordInput } from '@ark-ui/solid/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-solid'
export const RootProvider = () => {
const passwordInput = usePasswordInput()
return (
<>
<button onClick={() => passwordInput().focus()}>Focus</button>
<button onClick={() => passwordInput().setVisible(!passwordInput().visible)}>
{passwordInput().visible ? 'Hide' : 'Show'} Password
</button>
<PasswordInput.RootProvider value={passwordInput}>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.RootProvider>
</>
)
}
<script setup lang="ts">
import { PasswordInput, usePasswordInput } from '@ark-ui/vue/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-vue-next'
const passwordInput = usePasswordInput()
</script>
<template>
<button @click="passwordInput.focus()">Focus</button>
<PasswordInput.RootProvider :value="passwordInput">
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input placeholder="Enter your password" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator>
<EyeIcon />
<template #fallback>
<EyeOffIcon />
</template>
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.RootProvider>
</template>
Field
Here's an example of how to use the PasswordInput component with the Field component.
import { Field } from '@ark-ui/react/field'
import { PasswordInput } from '@ark-ui/react/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-react'
export const WithField = () => (
<Field.Root>
<PasswordInput.Root>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
<Field.HelperText>Enter your password</Field.HelperText>
<Field.ErrorText>Password is required</Field.ErrorText>
</Field.Root>
)
import { Field } from '@ark-ui/solid/field'
import { PasswordInput } from '@ark-ui/solid/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-solid'
export const WithField = () => (
<Field.Root>
<PasswordInput.Root>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
<Field.HelperText>Enter your password</Field.HelperText>
<Field.ErrorText>Password is required</Field.ErrorText>
</Field.Root>
)
<script setup lang="ts">
import { Field } from '@ark-ui/vue/field'
import { PasswordInput } from '@ark-ui/vue/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-vue-next'
</script>
<template>
<Field.Root>
<PasswordInput.Root>
<PasswordInput.Label>Password</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input placeholder="Enter your password" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator>
<EyeIcon />
<template #fallback>
<EyeOffIcon />
</template>
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
<Field.HelperText>Your password must be at least 8 characters</Field.HelperText>
<Field.ErrorText>Password is required</Field.ErrorText>
</Field.Root>
</template>
Ignoring password managers
Use the ignorePasswordManager prop to ignore password managers like 1Password, LastPass, etc. This is useful for
non-login scenarios (e.g., "api keys", "secure notes", "temporary passwords")
Currently, this only works for 1Password, LastPass, Bitwarden, Dashlane, and Proton Pass.
import { PasswordInput } from '@ark-ui/react/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-react'
export const IgnorePasswordManager = () => (
<PasswordInput.Root ignorePasswordManagers>
<PasswordInput.Label>API Key</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input defaultValue="spd_1234567890" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
import { PasswordInput } from '@ark-ui/solid/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-solid'
export const IgnorePasswordManager = () => (
<PasswordInput.Root ignorePasswordManagers>
<PasswordInput.Label>API Key</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input value="spd_1234567890" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
<script setup lang="ts">
import { PasswordInput } from '@ark-ui/vue/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-vue-next'
</script>
<template>
<PasswordInput.Root ignorePasswordManagers>
<PasswordInput.Label>API Key</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input value="spd_1234567890" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator>
<EyeIcon />
<template #fallback>
<EyeOffIcon />
</template>
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
</template>
Controlled visibility
Use the visible and onVisibilityChange props to control the visibility of the password input.
import { PasswordInput } from '@ark-ui/react/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-react'
import { useState } from 'react'
export const ControlledVisibility = () => {
const [visible, setVisible] = useState(false)
return (
<PasswordInput.Root visible={visible} onVisibilityChange={(e) => setVisible(e.visible)}>
<PasswordInput.Label>Password is {visible ? 'visible' : 'hidden'}</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
}
import { PasswordInput } from '@ark-ui/solid/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-solid'
import { createSignal } from 'solid-js'
export const ControlledVisibility = () => {
const [visible, setVisible] = createSignal(false)
return (
<PasswordInput.Root visible={visible()} onVisibilityChange={(e) => setVisible(e.visible)}>
<PasswordInput.Label>Password is {visible() ? 'visible' : 'hidden'}</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator fallback={<EyeOffIcon />}>
<EyeIcon />
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
)
}
<script setup lang="ts">
import { PasswordInput } from '@ark-ui/vue/password-input'
import { EyeIcon, EyeOffIcon } from 'lucide-vue-next'
import { ref } from 'vue'
const visible = ref(false)
</script>
<template>
<PasswordInput.Root v-model:visible="visible">
<PasswordInput.Label>Password is {{ visible ? 'visible' : 'hidden' }}</PasswordInput.Label>
<PasswordInput.Control>
<PasswordInput.Input placeholder="Enter your password" />
<PasswordInput.VisibilityTrigger>
<PasswordInput.Indicator>
<EyeIcon />
<template #fallback>
<EyeOffIcon />
</template>
</PasswordInput.Indicator>
</PasswordInput.VisibilityTrigger>
</PasswordInput.Control>
</PasswordInput.Root>
</template>
API Reference
Root
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
autoComplete | 'current-password' | 'current-password' | 'new-password'The autocomplete attribute for the password input. |
defaultVisible | booleanThe default visibility of the password input. | |
disabled | booleanWhether the password input is disabled. | |
id | stringThe unique identifier of the machine. | |
ids | Partial<{ input: string; visibilityTrigger: string }>The ids of the password input parts | |
ignorePasswordManagers | booleanWhen `true`, the input will ignore password managers. **Only works for the following password managers** - 1Password, LastPass, Bitwarden, Dashlane, Proton Pass | |
invalid | booleanThe invalid state of the password input. | |
name | stringThe name of the password input. | |
onVisibilityChange | (details: VisibilityChangeDetails) => voidFunction called when the visibility changes. | |
readOnly | booleanWhether the password input is read only. | |
required | booleanWhether the password input is required. | |
translations | Partial<{ visibilityTrigger: ((visible: boolean) => string) | undefined }>The localized messages to use. | |
visible | booleanWhether the password input is visible. |
Control
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Indicator
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. | |
fallback | string | number | bigint | boolean | ReactElement<unknown, string | JSXElementConstructor<any>> | Iterable<ReactNode> | ReactPortal | Promise<...>The fallback content to display when the password is not visible. |
Input
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
Label
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
RootProvider
| Prop | Default | Type |
|---|---|---|
value | UsePasswordInputReturn | |
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |
VisibilityTrigger
| Prop | Default | Type |
|---|---|---|
asChild | booleanUse the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |