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-part
attribute 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 | boolean Use 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 | boolean The default visibility of the password input. | |
disabled | boolean Whether the password input is disabled. | |
id | string The unique identifier of the machine. | |
ids | Partial<{ input: string; visibilityTrigger: string }> The ids of the password input parts | |
ignorePasswordManagers | boolean When `true`, the input will ignore password managers. **Only works for the following password managers** - 1Password, LastPass, Bitwarden, Dashlane, Proton Pass | |
invalid | boolean The invalid state of the password input. | |
name | string The name of the password input. | |
onVisibilityChange | (details: VisibilityChangeDetails) => void Function called when the visibility changes. | |
readOnly | boolean Whether the password input is read only. | |
required | boolean Whether the password input is required. | |
translations | Partial<{ visibilityTrigger: ((visible: boolean) => string) | undefined }> The localized messages to use. | |
visible | boolean Whether the password input is visible. |
Control
Prop | Default | Type |
---|---|---|
asChild | boolean Use 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 | boolean Use 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 | boolean Use 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 | boolean Use 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 | boolean Use 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 | boolean Use the provided child element as the default rendered element, combining their props and behavior. For more details, read our Composition guide. |