- Accordion
- AppShell
- Autocomplete
- Badge
- Blobatar
- BoringAvatar
- Button
- Calendar
- Checkbox
- DataGrid
- Date Picker
- Date Range Picker
- DateTime
- Dialog
- Drawer
- Dropdown
- Empty
- Error State
- Frame
- Input
- Input Amount
- Input Group
- Input OTP
- Input Password
- Input Phone
- Input Search
- Input Secret
- Loading
- PageContainer
- PageHeader
- Popover
- Select
- StatsCard
- Switch
- Tabs
- TextArea
- Toast
- Tooltip
Playground
"use client";
import { InputPassword } from "@/components/ui/input-password";
export function InputPasswordDemo() {
return (
<InputPassword
label={"Password"}
placeholder={"Enter password"}
autoComplete={"current-password"}
showPasswordLabel={"Show password"}
hidePasswordLabel={"Hide password"}
/>
);
}Installation
Initialize shadcn in your React project, then install this component from the Vandor UI registry:
$ pnpm dlx shadcn@latest add https://vandor-ui.vercel.app/r/input-password.json
The default installation target is components/ui/input-password.tsx. Review the CLI's overwrite prompt before replacing local customizations.
Dependencies
Installed automatically by the registry CLI. For manual setup:
- lucide-react
$ pnpm add lucide-reactUsage
import { InputPassword } from "@/components/ui/input-password";
<InputPassword label="Password" autoComplete="current-password" />;Set autoComplete="new-password" for account creation. The default visibility is hidden.
Examples
Choose autocomplete according to each field’s purpose so password managers can help users.
import { InputPassword } from "@/components/ui/input-password";
export const InputPasswordDemo = () => (
<div className="grid max-w-sm gap-4">
<InputPassword label="Current password" autoComplete="current-password" />
<InputPassword label="New password" autoComplete="new-password" />
</div>
);Optional Storybook Stories
Install Input Password first, then run npx shadcn@latest add https://vandor-ui.vercel.app/r/input-password-stories.json. Stories cover visibility toggling, label styles, controlled editing, and disabled/read-only/invalid states. Use fake credentials only; never enter real passwords in Storybook.
Stories install beside Input Password under your configured UI alias and use relative imports. Use your existing matching @storybook/react packages (verified with 10.6.1), discover **/*.stories.tsx, and load your global Tailwind/theme stylesheet. No addons, extra packages, core overwrites, or Storybook config edits are required. Default-value Controls remount uncontrolled examples; Controlled owns local state. Storybook UI is not verified because no server exists here.
Behavior & Accessibility
The show/hide button has a changing accessible name and does not submit a form. Existing password-manager attributes are forwarded. This component does not enforce password policy or strength.
Localize the action with showPasswordLabel="Tampilkan kata sandi" and hidePasswordLabel="Sembunyikan kata sandi". Defaults remain "Show password" and "Hide password". aria-pressed reflects visible state; a disabled field disables its visibility action too. The playground Reset remounts the field to restore hidden visibility. Only fake credentials belong in examples.
Props
| Prop | Type / Description | Default |
|---|---|---|
| autoComplete | "current-password" | "new-password"InputPassword: preserves browser password-manager hints. | native |
| defaultValue | stringInputPassword: initial uncontrolled value. | undefined |
| disabled | booleanInputPassword: prevents editing and visibility toggle. | false |
| label | stringInputPassword: visible associated label. | undefined |
| onChange | React.ChangeEventHandler<HTMLInputElement>InputPassword: native input change callback. | undefined |
| placeholder | stringInputPassword: native placeholder. | undefined |
| readOnly | booleanInputPassword: prevents editing but keeps focus and visibility controls. | false |
| showPasswordLabel | stringAccessible name while the password is hidden. | "Show password" |
| hidePasswordLabel | stringAccessible name while the password is visible. | "Hide password" |
| value | stringInputPassword: native controlled value. | uncontrolled |
The reference lists component-specific props and selected native props, not the complete React API. Other native attributes are forwarded to the rendered element.
Source
"use client";
import { Eye, EyeOff } from "lucide-react";
import * as React from "react";
import { Button } from "./button";
import { Input } from "./input";
import type { InputProps } from "./input";
export type InputPasswordProps = Omit<InputProps, "type" | "icon"> & {
showPasswordLabel?: string;
hidePasswordLabel?: string;
};
export const InputPassword = ({
className,
disabled,
readOnly,
showPasswordLabel = "Show password",
hidePasswordLabel = "Hide password",
...props
}: InputPasswordProps) => {
const [visible, setVisible] = React.useState(false);
return (
<div data-slot="password-input" className="relative min-w-0">
<Input
{...props}
type={visible ? "text" : "password"}
disabled={disabled}
readOnly={readOnly}
className={["pr-11", className].filter(Boolean).join(" ")}
/>
<Button
type="button"
variant="ghost"
size="icon-sm"
disabled={disabled}
aria-label={visible ? hidePasswordLabel : showPasswordLabel}
aria-pressed={visible}
className="absolute top-1/2 right-1 -translate-y-1/2"
onClick={() => setVisible((current) => !current)}
>
{visible ? <EyeOff aria-hidden="true" /> : <Eye aria-hidden="true" />}
</Button>
</div>
);
};