Password Field
Password input with a visibility toggle, Caps Lock detection, and a pluggable strength meter.
| Package | @vizejs/ui/password-field |
| Maturity | stable |
| Own the source | vize lib pull password-field |
| Requires | context, controllable-state, id |
| Aliases | password input, show password, reveal password, caps lock warning, password strength |
| Covers | HTML password input, WAI-ARIA Button (pressed), Chakra PasswordInput |
Minimal setup
Use a Vue 3.5+ project with Vue SFC compilation configured (see Vite+ integration).
vp install @vizejs/ui
Add the public import below to <script setup lang="ts">. Components provide behavior without styles; the preview uses optional Paper styles.
import { PasswordField, PasswordFieldInput, PasswordFieldToggle } from "@vizejs/ui/password-field";
Or copy the source into your project with vize lib pull password-field (see Source Distribution).
Try it
This is the basic example maintained with the component source, using the public package imports. The preview adds the optional Paper styles.
Open the interactive example · Styling these components
Copy the example
<!-- New-password field with a visibility toggle, Caps Lock warning, and strength meter. -->
<script setup lang="ts">
import { ref, useId } from "vue";
import {
PasswordField,
PasswordFieldInput,
PasswordFieldToggle,
estimatePasswordStrength,
} from "@vizejs/ui/password-field";
const password = ref("");
const inputId = useId();
const strengthId = useId();
</script>
<template>
<div>
<label :for="inputId">New password</label>
<PasswordField
:id="inputId"
v-slot="{ capsLock, strength }"
v-model="password"
name="password"
autocomplete="new-password"
:evaluate-strength="estimatePasswordStrength"
:aria-describedby="strengthId"
>
<PasswordFieldInput />
<PasswordFieldToggle v-slot="{ visible }">{{
visible ? "Hide" : "Show"
}}</PasswordFieldToggle>
<meter aria-label="Password strength" :min="0" :max="4" :value="strength?.score ?? 0"></meter>
<p :id="strengthId">Strength: {{ strength?.label ?? "none" }}</p>
<p v-if="capsLock" role="status">Caps Lock is on.</p>
</PasswordField>
</div>
</template>
API
PasswordField<Strength>
Source: src/families/form/password-field/password-field.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
id |
string | null |
undefined |
Id of the password input. null and undefined select a deterministic fallback. |
name |
string |
undefined |
Native form field name of the password input. |
modelValue |
string |
undefined |
Controlled password. undefined selects uncontrolled behavior. |
defaultValue |
string |
"" |
Initial uncontrolled password, also restored by form reset. |
visible |
boolean |
undefined |
Controlled visibility (v-model:visible). undefined selects uncontrolled behavior. |
defaultVisible |
boolean |
false |
Initial uncontrolled visibility. |
evaluateStrength |
(value: string) => Strength |
undefined |
Strength meter hook; its return type becomes the slot's strength. Pass estimatePasswordStrength or any custom evaluator. |
autocomplete |
string |
"current-password" |
Native autocomplete token: "current-password" for sign-in, "new-password" for sign-up. |
disabled |
boolean |
false |
Disable editing, the toggle, and native form submission. |
readOnly |
boolean |
false |
Keep the input focusable while preventing edits. |
required |
boolean |
false |
Mark the input as required for native constraint validation. |
ariaLabel |
string |
undefined |
Accessible name of the input when no label or aria-labelledby supplies one. |
ariaLabelledby |
string |
undefined |
Space-separated ids that label the input. |
ariaDescribedby |
string |
undefined |
Space-separated ids that describe the input. |
ariaErrormessage |
string |
undefined |
Id of the validation error message used while invalid. |
ariaInvalid |
PasswordFieldAriaInvalid |
false |
Invalid state announced to assistive technology. |
Events
| Event | Payload | Description |
|---|---|---|
update:modelValue |
[value: string] |
Fired when the password requests a new controlled value. |
update:visible |
[visible: boolean] |
Fired when visibility requests a new controlled value (v-model:visible). |
capsLockChange |
[active: boolean] |
Fired when Caps Lock turns on or off while typing in the input. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
PasswordFieldSlotState<Strength> |
Renders the input, toggle, and any hints with visibility, Caps Lock, and strength state. |
Exposed
| Member | Type | Description |
|---|---|---|
value |
string |
Current password. |
visible |
boolean |
Whether the password is shown as plain text. |
capsLock |
boolean |
Whether Caps Lock was on at the last key event inside the input. |
strength |
Strength | undefined |
Result of evaluateStrength, or undefined when no evaluator is supplied. |
disabled |
boolean |
Whether editing is disabled. |
readOnly |
boolean |
Whether edits are locked while focus remains available. |
state |
PasswordFieldState |
Stable state token. |
root |
HTMLDivElement | null |
Rendered root element. |
focus |
(options?: FocusOptions) => void |
Focus the password input. |
setVisible |
(visible: boolean) => boolean |
Show or hide the password; returns whether visibility changed. |
toggleVisible |
() => boolean |
Toggle visibility; returns the new visibility. |
setValue |
(value: string) => boolean |
Replace the password; returns whether it changed. |
reset |
() => void |
Restore the default password and visibility. |
PasswordFieldInput
Source: src/families/form/password-field/password-field-input.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder |
string |
undefined |
Native placeholder shown while empty. |
minlength |
number |
undefined |
Native minimum length for constraint validation. |
maxlength |
number |
undefined |
Native maximum length. |
PasswordFieldToggle
Source: src/families/form/password-field/password-field-toggle.vue
Props
| Prop | Type | Default | Description |
|---|---|---|---|
showLabel |
string |
"Show password" |
Accessible name while the password is hidden. |
hideLabel |
string |
"Hide password" |
Accessible name while the password is visible. |
Slots
| Slot | Slot props | Description |
|---|---|---|
default |
{ readonly visible: boolean } |
Toggle contents, typically an eye icon, with the current visibility. |
Behavior
Normative state x input -> outcome table for password-field.vue,
password-field-input.vue, and password-field-toggle.vue
(@vizejs/ui/password-field). The root is generic over the strength hook's
return type. Every row is proven by the named test in password-field.test.ts
or password-field-ssr.test.ts; compile-only assertions live in
password-field.types.test-d.ts.
| # | State | Input | Outcome | Proven by |
|---|---|---|---|---|
| P1 | any password | estimatePasswordStrength |
0-4 score and label from length and character variety; short passwords capped at "weak"; Unicode-aware checks | scores length and character variety with a dependency-free heuristic |
| P2 | named, seeded | render | native type="password" with current-password autocomplete, no autocapitalize/spellcheck, and a type="button" toggle with aria-pressed |
renders a native password input with sign-in autocomplete and a toggle |
| P3 | hidden | toggle press | pointer press keeps focus in the input; toggling swaps type, aria-pressed, the toggle label, and data-state, emitting update:visible |
the toggle reveals and hides the password while keeping focus in the input |
| P4 | controlled | toggle / typing | controlled visible and modelValue win until the parent accepts them |
controlled visibility and value win until the parent accepts them |
| P5 | typing | key events / blur | Caps Lock state follows getModifierState("CapsLock"), publishes data-caps-lock, emits capsLockChange, and clears on blur |
detects Caps Lock from key events and clears it on blur |
| P6 | strength hook | typing | evaluateStrength runs on every change and types the slot's strength; without it strength is undefined |
the strength hook evaluates every change and types the slot |
| P7 | in a form | reset | form reset restores defaultValue and hides the password |
form reset restores the password and hides it again |
| P8 | disabled/read-only | typing / toggle | disabled locks input and toggle; read-only keeps the value but still allows revealing it | disabled and read-only fields lock editing and the toggle appropriately |
| P9 | imperative | expose | focus, setValue, setVisible, toggleVisible, reset |
exposes focus, setValue, setVisible, toggleVisible, and reset |
| P10 | inside Field |
v-bind="fieldProps" |
id and ARIA relations reach the input; parts outside a PasswordField throw VIZE_UI_CONTEXT_MISSING |
binds Field fieldProps and requires a PasswordField provider for parts |
| P11 | SSR / hydration | isolated requests | byte-identical markup including slot-rendered strength, hydration without diagnostics, interactive toggle | renders byte-identical password markup and hydrates without mismatches |
Public extension contract
| Surface | Contract |
|---|---|
| Parts | root, input, toggle. |
| Data attributes | data-vize-ui, root data-state (hidden/visible/readonly/disabled), data-visible, data-caps-lock. |
| Slots | Root default slot receives PasswordFieldSlotState<Strength>; toggle slot receives { visible }. |
The subpath is tree-shakable and ships no CSS; those package contracts are
pinned by distribution.test.ts, check:size, and check:tree-shaking.