# Password

Compose password settings with the auth service and your own interface.

Import: @slices.sh/auth/headless

Public parts: 19

## Installation

### 1. Install the service registry

services/index.ts, which `import "@/services"` loads. A provider setup writes the same file; skip this if your app has one.

```bash
npx shadcn@latest add "https://slices.sh/r/services.json"
```

### 2. Install the headless library

```bash
npm install @slices.sh/auth@^0.1.10
```

### 3. Install the service

Install the provider configuration via shadcn or the slices CLI. Skip this step if your app already has the service configured. Provider commands and provisioning: https://slices.sh/docs/services/auth.md

## Anatomy

### Composition

```text
User.Root
  PasswordSettings.Root
    PasswordSettings.Available
      PasswordSettings.Status
      PasswordSettings.Begin
    PasswordSettings.Editing
      PasswordSettings.Existing
        PasswordSettings.Form
          PasswordSettings.Label field="current"
          PasswordSettings.Input field="current"
          PasswordSettings.Reveal
          PasswordSettings.CapsLock
          PasswordSettings.Strength
            PasswordSettings.StrengthSegment
          PasswordSettings.Feedback
          PasswordSettings.Requirement
          PasswordSettings.RevokeOthers
          PasswordSettings.Submit
          PasswordSettings.Cancel
        PasswordSettings.Label field="revoke"
      PasswordSettings.Error
```

## Minimal composition

```tsx
"use client"

import "@/services"
import { PasswordSettings } from "@slices.sh/auth/headless"

export function Example() {
  return (
    <PasswordSettings.Root>
      <PasswordSettings.Begin>Change password</PasswordSettings.Begin>
      <PasswordSettings.Editing>
        <PasswordSettings.Form>
          <PasswordSettings.Label field="current">
            Current password
          </PasswordSettings.Label>
          <PasswordSettings.Input field="current" />
          <PasswordSettings.Label field="new">
            New password
          </PasswordSettings.Label>
          <PasswordSettings.Input field="new" />
          <PasswordSettings.Submit>Save password</PasswordSettings.Submit>
          <PasswordSettings.Error />
        </PasswordSettings.Form>
      </PasswordSettings.Editing>
    </PasswordSettings.Root>
  )
}

```

Requires an authenticated account. Organization controls also require organizations and the appropriate role.

## Complete API reference

### PasswordSettings.Root

scope

Available gates the section where the backend can set passwords.

Import: @slices.sh/auth/headless

Capability: change-password

```tsx
RootProps & AuthRootProps
```

Alternate import: Root from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/root.tsx

### PasswordSettings.Available

gate

Available gates the section where the backend can set passwords.

Import: @slices.sh/auth/headless

Capability: change-password

```tsx
GateProps
```

Alternate import: Available from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/available.tsx

### PasswordSettings.Status

content · Element: p

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

```tsx
PartProps<"p", { hasPassword: boolean }>
```

Alternate import: Status from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/status.tsx

### PasswordSettings.Begin

action · Element: button

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

PasswordSettings.Begin requires Root.

```tsx
PartProps<"button", { hasPassword: boolean }>
```

Alternate import: Begin from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/begin.tsx

### PasswordSettings.Editing

gate

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

PasswordSettings.Editing requires Root.

```tsx
GateProps & { render?: ReactElement }
```

Alternate import: Editing from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/editing.tsx

### PasswordSettings.Existing

gate

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

```tsx
GateProps
```

Alternate import: Existing from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/existing.tsx

### PasswordSettings.Form

action · Element: form

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

PasswordSettings.Form requires Root.

```tsx
PartProps<"form">
```

Alternate import: Form from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/form.tsx

### PasswordSettings.Submit

action · Element: button

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

```tsx
PartProps<"button", { pending: boolean; retryAfter: number }>
```

Alternate import: Submit from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/submit.tsx

### PasswordSettings.Cancel

action · Element: button

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

PasswordSettings.Cancel requires Root.

```tsx
PartProps<"button">
```

Alternate import: Cancel from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/cancel.tsx

### PasswordSettings.Input

input · Element: input

Input takes field="current" | "new", Label the same plus revoke. RevokeOthers is the checkbox that signs out other sessions on change. Reveal toggles the new password's visibility; CapsLock speaks for the focused field.

Import: @slices.sh/auth/headless

PasswordSettings.Input requires Root.

```tsx
PartProps<"input"> & { field: "current" | "new" }
```

Alternate import: Input from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/input.tsx

### PasswordSettings.Label

content · Element: label

Input takes field="current" | "new", Label the same plus revoke. RevokeOthers is the checkbox that signs out other sessions on change. Reveal toggles the new password's visibility; CapsLock speaks for the focused field.

Import: @slices.sh/auth/headless

PasswordSettings.Label requires Root.

```tsx
PartProps<"label"> & { field: "current" | "new" | "revoke" }
```

Alternate import: Label from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/label.tsx

### PasswordSettings.RevokeOthers

input · Element: input

Input takes field="current" | "new", Label the same plus revoke. RevokeOthers is the checkbox that signs out other sessions on change. Reveal toggles the new password's visibility; CapsLock speaks for the focused field.

Import: @slices.sh/auth/headless

PasswordSettings.RevokeOthers requires Root.

```tsx
PartProps<"input">
```

Alternate import: RevokeOthers from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/revoke-others.tsx

### PasswordSettings.Error

content · Element: p

Status gets { hasPassword }. Begin opens the editor, with { hasPassword } so it can say add or change. Editing gates it and takes a motion render. Existing gates the current-password fields, for an account that has one. Form validates and writes; Submit has { pending, retryAfter }; Cancel closes. Error gets { message }.

Import: @slices.sh/auth/headless

PasswordSettings.Error requires Root.

```tsx
PartProps<"p", { message: string }>
```

Alternate import: Error from @slices.sh/auth/headless/password-settings

Source: @slices.sh/auth/src/headless/password-settings/error.tsx

### PasswordSettings.Strength

content · Element: div

The meter over a new password: `data-level` is the score, 0 to 4, and absent until one is
known.

Absent over an empty field too. A meter that says "very weak" before anything has been
typed is a screen telling somebody off for not having started.

Import: @slices.sh/auth/headless

PasswordStrength must be inside <SignIn.Root> or <SignUp.Root>.

```tsx
PartProps<"div", { score: number | null; levels: number }>
```

Source: @slices.sh/auth/src/headless/sign-in/password-strength.tsx

### PasswordSettings.StrengthSegment

content · Element: span

One bar of the meter, repeated once per level.

The count comes from the estimator's own scale rather than from the card, so a skin
cannot draw five bars over a score that only goes to four.

Import: @slices.sh/auth/headless

StrengthSegment must be inside <SignIn.Root> or <SignUp.Root>.

```tsx
Props

type Props = PartProps<"span", { index: number; filled: boolean }>
```

Source: @slices.sh/auth/src/headless/sign-in/strength-segment.tsx

### PasswordSettings.Requirement

content · Element: li

One rule a new password has to meet, said out loud rather than discovered by being
refused.

The numbers are the backend's, read from the capability, so the sentence and the refusal
can never disagree. `data-state` is `met` or `unmet`, which is what a skin ticks off. A
rule the backend does not have is absent: a "hard to guess" line over a backend that
accepts anything would be a promise nobody keeps.

Import: @slices.sh/auth/headless

PasswordRequirement must be inside <SignIn.Root> or <SignUp.Root>.

```tsx
PartProps<"li", State> & { rule: PasswordRule }

export type PasswordRule = "length" | "strength"

type State = { met: boolean; minLength: number; maxLength: number }
```

Source: @slices.sh/auth/src/headless/sign-in/password-requirement.tsx

### PasswordSettings.Feedback

content · Element: p

What the estimator would say about this password, in its own words.

Its sentences come from the language pack, so they are already the person's language and
are not repeated in `copy`. Absent until there is something to say: a strong password
earns no advice, and an empty field has not been judged.

Import: @slices.sh/auth/headless

PasswordFeedback must be inside <SignIn.Root> or <SignUp.Root>.

```tsx
PartProps<"p", { warning: string | null; suggestions: readonly string[] }>
```

Source: @slices.sh/auth/src/headless/sign-in/password-feedback.tsx

### PasswordSettings.Reveal

action · Element: button

Shows or hides what was typed into the password field.

No `aria-pressed`: its own name changes, and a button announced as "Hide password,
pressed" says the same thing twice in opposite directions.

Import: @slices.sh/auth/headless

SignIn.RevealPassword must be inside <SignIn.Root> or <SignUp.Root>.

```tsx
PartProps<"button", { visible: boolean }>
```

Source: @slices.sh/auth/src/headless/sign-in/reveal-password.tsx

### PasswordSettings.CapsLock

content · Element: p

Input takes field="current" | "new", Label the same plus revoke. RevokeOthers is the checkbox that signs out other sessions on change. Reveal toggles the new password's visibility; CapsLock speaks for the focused field.

Import: @slices.sh/auth/headless

CapsLock must be inside <SignIn.Root> or <SignUp.Root>.

```tsx
PartProps<"p", { active: boolean }>
```

Source: @slices.sh/auth/src/headless/sign-in/caps-lock.tsx

### User.Root

scope

Says which auth the User parts below read, and whether they may do without it. The parts need
no root: left out, they read the nearest auth root's config, or "default", and render nothing
without auth. `<User.Root enabled="optional">` is for the one who wants that said in the code.

Import: @slices.sh/auth/headless

```tsx
RootProps & AuthRootProps
```

Alternate import: User.Root from @slices.sh/auth/headless/user

Alternate import: User.Root from @slices.sh/auth/headless/passkeys

Alternate import: User.Root from @slices.sh/auth/headless/two-factor

Source: @slices.sh/auth/src/headless/user/root.tsx
