An input optimized for password and other sensitive-value entry. Renders a native <input type="password"> with a built-in trailing button that toggles between hidden (••••) and revealed (text) display.
Input.The toggle is uncontrolled by default. Pass showValue to control the visibility from the outside (useful when one UI control toggles multiple password fields), and onValueVisibilityChange to be notified when the user toggles via the built-in button.
Always pair with a Label. The toggle button has its own accessible name announcing the current state. The input keeps autocomplete="current-password" / "new-password" semantics — set autoComplete explicitly per flow.
When revealed, the input switches to type="text" — some password managers may pause autofill in this state, which is the intended security tradeoff.
Pair with Field.* for label/description/error wiring in forms:
1import { Field } from "@ngrok/mantle/field";2import { PasswordInput } from "@ngrok/mantle/input";3 4<Field.Item className="max-w-64" name="password">5 <Field.Label>Password</Field.Label>6 <Field.Control>7 <PasswordInput />8 </Field.Control>9</Field.Item>10<Field.Item className="max-w-64" name="password-error">11 <Field.Label>Password (error)</Field.Label>12 <Field.Control>13 <PasswordInput validation="error" />14 </Field.Control>15</Field.Item>Or render the control on its own:
1import { PasswordInput } from "@ngrok/mantle/input";2 3<PasswordInput aria-label="Password" />;Use @tanstack/react-form with zod to validate a controlled PasswordInput inside Field.Item.
1import { Button } from "@ngrok/mantle/button";2import { Field, toErrorMessages } from "@ngrok/mantle/field";3import { PasswordInput } from "@ngrok/mantle/input";4import { useForm } from "@tanstack/react-form";5import { z } from "zod";6 7export const formSchema = z.object({8 password: z.string().min(8, "Use at least 8 characters."),9});10function Example() {11 const defaultValues = {12 password: "",13 };14 const form = useForm({15 defaultValues,16 validators: {17 onSubmit: formSchema,18 },19 onSubmit: ({ value }) => {20 // Handle form submission here21 },22 });23 24 return (25 <form26 onSubmit={(event) => {27 event.preventDefault();28 event.stopPropagation();29 void form.handleSubmit();30 }}31 >32 <form.Field name="password">33 {(field) => (34 <Field.Item name={field.name}>35 <Field.Label>Password</Field.Label>36 <Field.Control>37 <PasswordInput38 value={field.state.value}39 onBlur={field.handleBlur}40 onChange={(event) => field.handleChange(event.target.value)}41 autoComplete="new-password"42 />43 </Field.Control>44 <Field.Errors messages={toErrorMessages(field.state.meta.errors)} />45 </Field.Item>46 )}47 </form.Field>48 <Button type="submit" appearance="filled">49 Submit50 </Button>51 </form>52 );53}The PasswordInput accepts the following props in addition to the standard HTML input attributes.