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

Headless / Account

Connected accounts

Compose connected accounts with the auth service and your own interface.

18 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 --auth-methods google

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 { Accounts } from "@slices.sh/auth/headless"export function Example() {  return (    <Accounts.Root>      <Accounts.Connect>        {({ provider }) => <>Connect {provider}</>}      </Accounts.Connect>      <Accounts.Item>        <Accounts.ActionTrigger>Disconnect</Accounts.ActionTrigger>        <Accounts.UnlinkDialog>          <Accounts.Confirm>Confirm</Accounts.Confirm>          <Accounts.Cancel>Cancel</Accounts.Cancel>        </Accounts.UnlinkDialog>      </Accounts.Item>      <Accounts.Error />    </Accounts.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.

Accounts.Rootscope

Available gates the section where the backend links providers after sign-up.

Capability: linked-accounts

Props

3 documented props

Accounts.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
  • Accounts.Root from @slices.sh/auth/headless/accounts

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

Accounts.Availablegate

Available gates the section where the backend links providers after sign-up.

Capability: linked-accounts

Props

1 documented props

Accounts.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
  • Accounts.Available from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/available.tsx

Accounts.Loadinggate

Loading, Empty, Error and Retry for the linked accounts; MethodsError and MethodsRetry for the sign-in methods read beside them.

Props

1 documented props

Accounts.Loading 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
  • Accounts.Loading from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/loading.tsx

Accounts.Emptygate

Loading, Empty, Error and Retry for the linked accounts; MethodsError and MethodsRetry for the sign-in methods read beside them.

Props

1 documented props

Accounts.Empty 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
  • Accounts.Empty from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/empty.tsx

Accounts.Errorcontent · <p>

Loading, Empty, Error and Retry for the linked accounts; MethodsError and MethodsRetry for the sign-in methods read beside them.

Props

2 documented props · Native <p> attributes supported

Accounts.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
  • Accounts.Error from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/error.tsx

Accounts.Retryaction · <button>

Loading, Empty, Error and Retry for the linked accounts; MethodsError and MethodsRetry for the sign-in methods read beside them.

Props

2 documented props · Native <button> attributes supported

Accounts.Retry 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
  • Accounts.Retry from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/retry.tsx

Accounts.MethodsErrorcontent · <p>

Loading, Empty, Error and Retry for the linked accounts; MethodsError and MethodsRetry for the sign-in methods read beside them.

Props

2 documented props · Native <p> attributes supported

Accounts.MethodsError 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
  • Accounts.MethodsError from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/methods-error.tsx

Accounts.MethodsRetryaction · <button>

Loading, Empty, Error and Retry for the linked accounts; MethodsError and MethodsRetry for the sign-in methods read beside them.

Props

2 documented props · Native <button> attributes supported

Accounts.MethodsRetry 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
  • Accounts.MethodsRetry from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/methods-retry.tsx

Accounts.Itemcontent · <li>

Item repeats once per linked account with { provider, account }. OnlyMethod opens inside the row that is the account's last way in. Connect links a provider, with { provider, pending, retryAfter }. LinkError reports a refused link, CallbackError a provider that came back with an error.

Capability: methods: oauth

Required scope

Accounts.Item provides its own scope.

Props

2 documented props · Native <li> attributes supported

Accounts.Item props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { provider: OAuthProvider; account: string | null }) => 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
  • Accounts.Item from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/item.tsx

Accounts.OnlyMethodgate

Item repeats once per linked account with { provider, account }. OnlyMethod opens inside the row that is the account's last way in. Connect links a provider, with { provider, pending, retryAfter }. LinkError reports a refused link, CallbackError a provider that came back with an error.

Capability: methods: oauth

Props

1 documented props

Accounts.OnlyMethod 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
  • Accounts.OnlyMethod from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/only-method.tsx

Accounts.Connectaction · <button>

Item repeats once per linked account with { provider, account }. OnlyMethod opens inside the row that is the account's last way in. Connect links a provider, with { provider, pending, retryAfter }. LinkError reports a refused link, CallbackError a provider that came back with an error.

Capability: methods: oauth

Required scope

Accounts.Connect requires Accounts.Root.

Props

2 documented props · Native <button> attributes supported

Accounts.Connect props
PropTypeDefault
children

Content rendered inside this part.

ReactNode | ((state: { provider: OAuthProvider; 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
  • Accounts.Connect from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/connect.tsx

Accounts.LinkErrorcontent · <p>

Item repeats once per linked account with { provider, account }. OnlyMethod opens inside the row that is the account's last way in. Connect links a provider, with { provider, pending, retryAfter }. LinkError reports a refused link, CallbackError a provider that came back with an error.

Capability: methods: oauth

Required scope

Accounts.LinkError requires Accounts.Root.

Props

2 documented props · Native <p> attributes supported

Accounts.LinkError 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
  • Accounts.LinkError from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/link-error.tsx

Accounts.CallbackErrorcontent · <p>

Item repeats once per linked account with { provider, account }. OnlyMethod opens inside the row that is the account's last way in. Connect links a provider, with { provider, pending, retryAfter }. LinkError reports a refused link, CallbackError a provider that came back with an error.

Capability: methods: oauth

Props

2 documented props · Native <p> attributes supported

Accounts.CallbackError 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
  • Accounts.CallbackError from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/callback-error.tsx

Accounts.UnlinkDialogcontent

UnlinkDialog maps onto render={<AlertDialog />}. ActionTrigger arms it, Confirm unlinks with { pending, retryAfter }, Cancel disarms, ActionError gets { message }.

Required scope

Accounts.UnlinkDialog requires a connection row.

Props

2 documented props

Accounts.UnlinkDialog 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
  • Accounts.UnlinkDialog from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/unlink-dialog.tsx

Accounts.ActionTriggeraction · <button>

UnlinkDialog maps onto render={<AlertDialog />}. ActionTrigger arms it, Confirm unlinks with { pending, retryAfter }, Cancel disarms, ActionError gets { message }.

Required scope

Accounts.ActionTrigger requires Accounts.Root.

Props

2 documented props · Native <button> attributes supported

Accounts.ActionTrigger 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
  • Accounts.ActionTrigger from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/action-trigger.tsx

Accounts.Cancelaction · <button>

UnlinkDialog maps onto render={<AlertDialog />}. ActionTrigger arms it, Confirm unlinks with { pending, retryAfter }, Cancel disarms, ActionError gets { message }.

Required scope

Accounts.Cancel requires Accounts.Root.

Props

2 documented props · Native <button> attributes supported

Accounts.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
  • Accounts.Cancel from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/cancel.tsx

Accounts.Confirmaction · <button>

UnlinkDialog maps onto render={<AlertDialog />}. ActionTrigger arms it, Confirm unlinks with { pending, retryAfter }, Cancel disarms, ActionError gets { message }.

Required scope

Accounts.Confirm requires a connection row.

Props

2 documented props · Native <button> attributes supported

Accounts.Confirm 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
  • Accounts.Confirm from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/confirm.tsx

Accounts.ActionErrorcontent · <p>

UnlinkDialog maps onto render={<AlertDialog />}. ActionTrigger arms it, Confirm unlinks with { pending, retryAfter }, Cancel disarms, ActionError gets { message }.

Required scope

Accounts.ActionError requires Accounts.Root.

Props

2 documented props · Native <p> attributes supported

Accounts.ActionError 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
  • Accounts.ActionError from @slices.sh/auth/headless/accounts

Source: @slices.sh/auth/src/headless/accounts/action-error.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 →