Skip to content
SLICES / TECHNICAL FOLIO Nº 001FULL-STACK ASSEMBLIES — OPEN SOURCE

Headless / Account

Password

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

19 public parts · 1examples

@slices.sh/auth/headlessView as Markdown ↗

Your design. Our behavior.

Explore the tree to see what each part controls. Gates reveal the relevant state; roots outline their scope.

Behavior / inputGateGenericRenderer · not headlessScope
COMPONENT ANATOMYHover · focus · tap
ONE POSSIBLE DESIGNStatic preview

User.Root · Scope

User.RootSays 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.

Installation

Choose what your component needs. Run these commands in an initialized Next.js app.

0

Before you start

The steps below run in a Next.js app with shadcn set up (it has a components.json). In an existing Next.js app, such as one from create-next-app, set shadcn up first:

npx shadcn@latest init -t next -b base -p nova

Or start fresh: the slices CLI creates the app and sets it up.

npx slices.sh install
1

Install the service registry

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

npx add services
2

Install the headless library

npm

Add the React parts to your app, then compose them with your own elements.

npm install @slices.sh/auth@^0.1.10

Import from @slices.sh/auth/headless.

3

Install the service

Connect the parts to a provider. Skip this step if this service is already configured in your app.

Provider
Database
Authentication methods
Account capabilities
npx add auth.betterauth

Adds service configuration and API routes to your app, with the provider dependencies. For a headless composition, add import "@/services" after "use client".

The slices CLI installs the service and provisions its required resources in one command.

Set BETTER_AUTH_URL to your app origin. Memory is for local development; use a persistent database for deployment. Neon and Supabase also require the migration script printed by the installer.

Provider setup notes
  • BETTER_AUTH_SECRET signs every session and is generated into .env.local while this installs (32 random bytes, base64, nothing leaves the machine). Changing it signs everyone out; in production set the same one on every instance.
  • The public origin (OAuth callbacks, the passkey domain) is the one each request comes to in development, and the deployment's own on Vercel. Elsewhere, or behind a proxy or a custom domain, set BETTER_AUTH_URL, such as https://acme.com.

Start small

Parts bring the behavior. Use their default elements, or supply your own with render.

example.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.

API reference

Every public part used by this experience is listed below. Gates render children without adding an element. Element parts accept native element props and render; function children receive the state declared in their props. Scopes provide context rather than a visual element.

PasswordSettings.Rootscope

Available gates the section where the backend can set passwords.

Capability: change-password

Props

3 documented props

PasswordSettings.Root props
PropTypeDefault
config

The auth config, a slug from the registry (services/auth/<config>.config.ts). The nearest root's, else "default", when left out.

string—
enabled

Left out or true: required, and missing auth throws. "optional": renders its children and every part inside degrades without auth. false: off. A capability name such as "methods: password": requires auth with it.

Enabled—
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Root from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Availablegate

Available gates the section where the backend can set passwords.

Capability: change-password

Props

1 documented props

PasswordSettings.Available props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Available from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Statuscontent · <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 }.

Props

2 documented props · Native <p> attributes supported

PasswordSettings.Status props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { hasPassword: boolean }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Status from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Beginaction · <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 }.

Required scope

PasswordSettings.Begin requires Root.

Props

2 documented props · Native <button> attributes supported

PasswordSettings.Begin props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { hasPassword: boolean }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Begin from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Editinggate

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 }.

Required scope

PasswordSettings.Editing requires Root.

Props

2 documented props

PasswordSettings.Editing props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render
ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Editing from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Existinggate

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 }.

Props

1 documented props

PasswordSettings.Existing props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Existing from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Formaction · <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 }.

Required scope

PasswordSettings.Form requires Root.

Props

2 documented props · Native <form> attributes supported

PasswordSettings.Form props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Form from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Submitaction · <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 }.

Props

2 documented props · Native <button> attributes supported

PasswordSettings.Submit props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { pending: boolean; retryAfter: number }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Submit from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Cancelaction · <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 }.

Required scope

PasswordSettings.Cancel requires Root.

Props

2 documented props · Native <button> attributes supported

PasswordSettings.Cancel props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Cancel from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Inputinput · <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.

Required scope

PasswordSettings.Input requires Root.

Props

3 documented props · Native <input> attributes supported

PasswordSettings.Input props
PropTypeDefault
fieldRequired
"current" | "new"—
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Input from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Labelcontent · <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.

Required scope

PasswordSettings.Label requires Root.

Props

3 documented props · Native <label> attributes supported

PasswordSettings.Label props
PropTypeDefault
fieldRequired
"current" | "new" | "revoke"—
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Label from @slices.sh/auth/headless/password-settings

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

PasswordSettings.RevokeOthersinput · <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.

Required scope

PasswordSettings.RevokeOthers requires Root.

Props

2 documented props · Native <input> attributes supported

PasswordSettings.RevokeOthers props
PropTypeDefault
children

Content rendered inside this part.

ReactNode—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • RevokeOthers from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Errorcontent · <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 }.

Required scope

PasswordSettings.Error requires Root.

Props

2 documented props · Native <p> attributes supported

PasswordSettings.Error props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { message: string }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • Error from @slices.sh/auth/headless/password-settings

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

PasswordSettings.Strengthcontent · <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.

Required scope

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

Props

2 documented props · Native <div> attributes supported

PasswordSettings.Strength props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { score: number | null; levels: number }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

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

PasswordSettings.StrengthSegmentcontent · <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.

Required scope

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

Props

2 documented props · Native <span> attributes supported

PasswordSettings.StrengthSegment props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { index: number; filled: boolean }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

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

PasswordSettings.Requirementcontent · <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.

Required scope

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

Props

3 documented props · Native <li> attributes supported

PasswordSettings.Requirement props
PropTypeDefault
ruleRequired
"length" | "strength"—
children

Content rendered inside this part.

ReactNode | ((state: State) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

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

PasswordSettings.Feedbackcontent · <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.

Required scope

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

Props

2 documented props · Native <p> attributes supported

PasswordSettings.Feedback props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { warning: string | null; suggestions: readonly string[] }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

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

PasswordSettings.Revealaction · <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.

Required scope

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

Props

2 documented props · Native <button> attributes supported

PasswordSettings.Reveal props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { visible: boolean }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

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

PasswordSettings.CapsLockcontent · <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.

Required scope

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

Props

2 documented props · Native <p> attributes supported

PasswordSettings.CapsLock props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { active: boolean }) => ReactNode)—
render

Replace the default element with your own while retaining the part’s behavior and accessibility.

ReactElement—

Required props are marked. A dash means no explicit default is declared in this component.

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

User.Rootscope

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.

Props

3 documented props

User.Root props
PropTypeDefault
config

The auth config, a slug from the registry (services/auth/<config>.config.ts). The nearest root's, else "default", when left out.

string—
enabled

Left out or true: required, and missing auth throws. "optional": renders its children and every part inside degrades without auth. false: off. A capability name such as "methods: password": requires auth with it.

Enabled—
children

Content rendered inside this part.

ReactNode—

Required props are marked. A dash means no explicit default is declared in this component.

Alternate public imports
  • User.Root from @slices.sh/auth/headless/user
  • User.Root from @slices.sh/auth/headless/passkeys
  • User.Root from @slices.sh/auth/headless/two-factor

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

When something is missing

No service configuration
Install the auth setup below and import "@/services". Required service roots report missing setup; gates do not replace that configuration.
Missing capability or parent scope
Follow each part’s context requirements and the example composition. Capability-aware controls hide when the provider cannot perform their action.
Read the setup guide →