Skip to content

PasswordInput

Form

Labeled password entry with an accessible visibility toggle.

New passwordPrefilled current passwordDisabled managed password
Open preview

Responsive viewport — resize the window to explore. Direction and density apply only to this preview. Theme applies to the docs too.

Usage

Use this input for current or new passwords, with an appropriate autoComplete value. It forwards ordinary Input props, including name, required, disabled, value, defaultValue, and onChange. Visibility is local state; changing it preserves the input value. Place any validation or policy guidance nearby.

Import
import { PasswordInput } from "@/components/ui/password-input";

Shipped as editable source in src/components/ui/password-input.tsx in both apps. Copy the implementation below when moving it to another project. Copy the complete example from Source code for all imports and state. Add "use client" when using hooks or event handlers. See installation and theming for project setup.

Component source

The complete implementation is included in both apps. It uses the React, Radix, Lucide, and shared-core dependencies already installed in Apex. Keep your project’s semantic theme tokens when reusing it.

src/components/ui/password-input.tsx
"use client";
import { useId, useState, type ComponentProps } from "react";
import { Eye, EyeOff } from "lucide-react";
import { Input } from "@dashboardpack/core/components/ui/input";
import { Label } from "@dashboardpack/core/components/ui/label";
import { cn } from "@dashboardpack/core/lib/utils";
export interface PasswordInputProps
  extends Omit<ComponentProps<typeof Input>, "type"> {
  label: string;
}
export function PasswordInput({
  label,
  id,
  className,
  disabled,
  ...props
}: PasswordInputProps) {
  const generatedId = useId();
  const inputId = id ?? generatedId;
  const [visible, setVisible] = useState(false);
  return (
    <div className={cn("space-y-2", className)}>
      <Label htmlFor={inputId}>{label}</Label>
      <div className="relative">
        <Input
          {...props}
          id={inputId}
          disabled={disabled}
          type={visible ? "text" : "password"}
          className="pe-12"
        />
        <button
          type="button"
          disabled={disabled}
          aria-label={`${visible ? "Hide" : "Show"} ${label}`}
          aria-pressed={visible}
          aria-controls={inputId}
          onClick={() => setVisible(!visible)}
          className="absolute inset-y-0 end-0 flex w-11 items-center justify-center rounded-e-md text-muted-foreground hover:text-foreground focus-visible:outline-2 focus-visible:outline-ring disabled:opacity-50"
        >
          {visible ? <EyeOff className="size-4" /> : <Eye className="size-4" />}
        </button>
      </div>
    </div>
  );
}

API reference

Common props and defaults. Slot-specific props are named below; native elements also accept their standard HTML attributes. The component TypeScript definitions are the complete type reference.

PasswordInput props
PropType / DefaultDescription
labelstring

Default: required

Visible field label and the basis of the toggle accessible name.
idstring

Default: generated

Override the generated input id for external help and validation links.
autoCompletestring

Default: —

Use current-password or new-password to assist password managers.
disabledboolean

Default: false

Disable the field and visibility control.
value / defaultValueInput value

Default: —

Use controlled value plus onChange, or uncontrolled defaultValue.
onChangeChangeEventHandler<HTMLInputElement>

Default: —

Receive edits using the ordinary input event.
classNamestring

Default: —

Extend the component container with theme-aware utility classes.

Build with these too