# Password Field

A password input with a button that shows and hides what's typed.

Source: [password-field.tsx](https://github.com/jakejarvis/jarvis-ui/blob/main/src/components/ui/password-field.tsx)

```tsx
import { Field, FieldLabel } from "@/components/ui/field";
import { PasswordField } from "@/components/ui/password-field";

export default function PasswordFieldBasic() {
  return (
    <Field className="max-w-sm">
      <FieldLabel>Password</FieldLabel>
      <PasswordField autoComplete="current-password" defaultValue="correct-horse" />
    </Field>
  );
}
```

## Installation

Add the registry, once per project:

```bash
npx shadcn@latest registry add @jarvis=https://ui.jarv.is/r/{name}.json
```

Then add the component:

```bash
npx shadcn@latest add @jarvis/password-field
```

## Usage

```tsx
import { Field, FieldLabel } from "@/components/ui/field";
import { PasswordField } from "@/components/ui/password-field";

export function SignInPassword() {
  return (
    <Field>
      <FieldLabel>Password</FieldLabel>
      <PasswordField autoComplete="current-password" />
    </Field>
  );
}
```

Password Field is an [Input](https://ui.jarv.is/components/input.md) with an eye button at its end, which switches the
input between `type="password"` and `type="text"`. It takes everything Input does but `type`,
including `size` and `variant`, and the button follows its size, its variant and its disabled
state, including a disabled [Field](https://ui.jarv.is/components/field.md)'s. `className` and `style` go on the wrapper
around the two, and every other prop on the input.

Set `autoComplete` so password managers know what to fill: `current-password` for signing in and
`new-password` for signing up or changing it. Spellcheck, autocorrect and autocapitalization are
off, so a shown password isn't sent to a spellchecker or changed as it's typed.

To show a secret the reader can't edit, such as an API key, use
[Secret Field](https://ui.jarv.is/components/secret-field.md).

## Examples

### New password

```tsx
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
import { PasswordField } from "@/components/ui/password-field";

export default function PasswordFieldNewPassword() {
  return (
    <Field className="max-w-sm">
      <FieldLabel>New password</FieldLabel>
      <PasswordField autoComplete="new-password" minLength={12} defaultValue="battery-staple-42" />
      <FieldDescription>Use at least 12 characters.</FieldDescription>
    </Field>
  );
}
```

### Controlled

`revealed` and `onRevealedChange` control whether the password shows, here for two fields at once.

```tsx
import * as React from "react";

import { Checkbox } from "@/components/ui/checkbox";
import { Field, FieldGroup, FieldLabel } from "@/components/ui/field";
import { PasswordField } from "@/components/ui/password-field";

export default function PasswordFieldControlled() {
  const [revealed, setRevealed] = React.useState(false);

  return (
    <FieldGroup className="max-w-sm">
      <Field>
        <FieldLabel>New password</FieldLabel>
        <PasswordField
          autoComplete="new-password"
          defaultValue="battery-staple-42"
          revealed={revealed}
          onRevealedChange={setRevealed}
        />
      </Field>
      <Field>
        <FieldLabel>Confirm password</FieldLabel>
        <PasswordField
          autoComplete="new-password"
          defaultValue="battery-staple-42"
          revealed={revealed}
          onRevealedChange={setRevealed}
        />
      </Field>
      <Field orientation="horizontal">
        <Checkbox
          id="show-passwords"
          checked={revealed}
          onCheckedChange={(checked) => setRevealed(checked)}
        />
        <FieldLabel htmlFor="show-passwords">Show passwords</FieldLabel>
      </Field>
    </FieldGroup>
  );
}
```

### Sizes

```tsx
import { PasswordField } from "@/components/ui/password-field";

export default function PasswordFieldSizes() {
  return (
    <div className="flex w-full max-w-sm flex-col gap-4">
      <PasswordField size="sm" aria-label="Small password" defaultValue="correct-horse" />
      <PasswordField aria-label="Default password" defaultValue="correct-horse" />
      <PasswordField size="lg" aria-label="Large password" defaultValue="correct-horse" />
    </div>
  );
}
```

### Invalid

```tsx
import { Field, FieldError, FieldLabel } from "@/components/ui/field";
import { PasswordField } from "@/components/ui/password-field";

export default function PasswordFieldInvalid() {
  return (
    <Field invalid className="max-w-sm">
      <FieldLabel>Password</FieldLabel>
      <PasswordField autoComplete="new-password" defaultValue="hunter2" />
      <FieldError>Use at least 12 characters.</FieldError>
    </Field>
  );
}
```

### Disabled

```tsx
import { Field, FieldLabel } from "@/components/ui/field";
import { PasswordField } from "@/components/ui/password-field";

export default function PasswordFieldDisabled() {
  return (
    <Field disabled className="max-w-sm">
      <FieldLabel>Password</FieldLabel>
      <PasswordField defaultValue="correct-horse" />
    </Field>
  );
}
```

## Props

| Part | Extends |
| --- | --- |
| `PasswordField` | [`Input`](https://ui.jarv.is/components/input.md) |

### PasswordField

| Prop                | Type                            | Description                                                            |
| ------------------- | ------------------------------- | ---------------------------------------------------------------------- |
| `variant?`          | `"default" \| "underline"`      | Default: `"default"`                                                   |
| `size?`             | `"default" \| "lg" \| "sm"`     | The height: `sm` 24px, `default` 28px, `lg` 32px. Default: `"default"` |
| `revealed?`         | `boolean`                       | Whether the password shows as plain text.                              |
| `defaultRevealed?`  | `boolean`                       | Default: `false`                                                       |
| `onRevealedChange?` | `((revealed: boolean) => void)` |                                                                        |
| `className?`        | `string`                        | CSS class applied to the element.                                      |
| `style?`            | `React.CSSProperties`           | Style applied to the element.                                          |
