# Join requests

Review and approve or reject workspace access requests.

Import: @slices.sh/auth/headless

Public parts: 14

## 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
  Organization.RequestJoin.Root
    Organization.RequestJoin.Submit
    Organization.RequestJoin.Result
    Organization.RequestJoin.Error
  Organization.Active
    Members.Requests.Access
      Members.Requests.Row
        Members.Requests.Approve
        Members.Requests.Reject
        Members.Requests.DecisionError
      Members.Requests.Count
      Members.Requests.Refresh
  Members.Requests.Loading
  Members.Requests.Empty
  Members.Requests.Error
```

## Minimal composition

```tsx
"use client"

import "@/services"
import { User, Members } from "@slices.sh/auth/headless"

export function Example() {
  return (
    <User.Root>
      <Members.Requests.Row>
        <Members.Requests.Approve>Approve</Members.Requests.Approve>
        <Members.Requests.Reject>Decline</Members.Requests.Reject>
        <Members.Requests.DecisionError />
      </Members.Requests.Row>
      <Members.Requests.Empty>No pending requests.</Members.Requests.Empty>
    </User.Root>
  )
}

```

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

## Request access

```tsx
"use client"

import "@/services"
import { User, Organization } from "@slices.sh/auth/headless"

export function Example() {
  return (
    <User.Root>
      <Organization.RequestJoin.Root organizationId="workspace-id">
        <Organization.RequestJoin.Submit>
          Request access
        </Organization.RequestJoin.Submit>
        <Organization.RequestJoin.Result>
          Request received.
        </Organization.RequestJoin.Result>
        <Organization.RequestJoin.Error />
      </Organization.RequestJoin.Root>
    </User.Root>
  )
}

```

Supply a known workspace ID; this does not expose public workspace discovery.

## Complete API reference

### Organization.RequestJoin.Root

scope

The host supplies a known organization; this does not expose public discovery.

Import: @slices.sh/auth/headless

```tsx
Props

type Props = RootProps & { organizationId: string }
```

Alternate import: Organization.RequestJoin.Root from @slices.sh/auth/headless/organization

Source: @slices.sh/auth/src/headless/organization/request-join/root.tsx

### Organization.RequestJoin.Submit

action · Element: button

Organization.RequestJoin.Submit renders a button element.

Import: @slices.sh/auth/headless

RequestJoin.Submit requires RequestJoin.Root.

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

Alternate import: Organization.RequestJoin.Submit from @slices.sh/auth/headless/organization

Source: @slices.sh/auth/src/headless/organization/request-join/submit.tsx

### Organization.RequestJoin.Result

content · Element: p

Organization.RequestJoin.Result renders a p element.

Import: @slices.sh/auth/headless

RequestJoin.Result requires RequestJoin.Root.

```tsx
PartProps<"p", { status: JoinRequest["status"] | null }>
```

Alternate import: Organization.RequestJoin.Result from @slices.sh/auth/headless/organization

Source: @slices.sh/auth/src/headless/organization/request-join/result.tsx

### Organization.RequestJoin.Error

content · Element: p

Organization.RequestJoin.Error renders a p element.

Import: @slices.sh/auth/headless

RequestJoin.Error requires RequestJoin.Root.

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

Alternate import: Organization.RequestJoin.Error from @slices.sh/auth/headless/organization

Source: @slices.sh/auth/src/headless/organization/request-join/error.tsx

### Members.Requests.Access

gate

Members.Requests.Access conditionally renders its children.

Import: @slices.sh/auth/headless

```tsx
GateProps
```

Alternate import: Members.Requests.Access from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/access.tsx

### Members.Requests.Row

content · Element: li

Members.Requests.Row renders a li element.

Import: @slices.sh/auth/headless

Requests.Row supplies its own request.

```tsx
Props

type Props = PartProps<"li", { request: JoinRequest }>
```

Alternate import: Members.Requests.Row from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/row.tsx

### Members.Requests.Approve

action · Element: button

Members.Requests.Approve renders a button element.

Import: @slices.sh/auth/headless

Requests.Approve requires Requests.Row.

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

Alternate import: Members.Requests.Approve from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/approve.tsx

### Members.Requests.Reject

action · Element: button

Members.Requests.Reject renders a button element.

Import: @slices.sh/auth/headless

Requests.Reject requires Requests.Row.

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

Alternate import: Members.Requests.Reject from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/reject.tsx

### Members.Requests.DecisionError

content · Element: p

Members.Requests.DecisionError renders a p element.

Import: @slices.sh/auth/headless

Requests.DecisionError requires Requests.Row.

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

Alternate import: Members.Requests.DecisionError from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/decision-error.tsx

### Members.Requests.Count

content · Element: span

Members.Requests.Count renders a span element.

Import: @slices.sh/auth/headless

```tsx
PartProps<"span", { count: number }>
```

Alternate import: Members.Requests.Count from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/count.tsx

### Members.Requests.Empty

gate

Members.Requests.Empty conditionally renders its children.

Import: @slices.sh/auth/headless

```tsx
GateProps
```

Alternate import: Members.Requests.Empty from @slices.sh/auth/headless/members

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

### Members.Requests.Loading

gate

Members.Requests.Loading conditionally renders its children.

Import: @slices.sh/auth/headless

```tsx
GateProps
```

Alternate import: Members.Requests.Loading from @slices.sh/auth/headless/members

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

### Members.Requests.Error

content · Element: div

Members.Requests.Error renders a div element.

Import: @slices.sh/auth/headless

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

Alternate import: Members.Requests.Error from @slices.sh/auth/headless/members

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

### Members.Requests.Refresh

action · Element: button

Members.Requests.Refresh renders a button element.

Import: @slices.sh/auth/headless

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

Alternate import: Members.Requests.Refresh from @slices.sh/auth/headless/members

Source: @slices.sh/auth/src/headless/members/requests/refresh.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

### Organization.Active

gate

Item is a <button> repeated once per organization with { active, pending }; clicking makes it active. Personal switches to the personal account. Active renders its children with the active organization in scope, and nothing on the personal account; None is its mirror, once the answer is in. Switcher holds the searchable list: Switcher.Surface maps onto a Popover or a Sheet, Switcher.Options, Input, List, Item, Empty and Error search and list, and Switcher.Shortcuts binds keys to switch.

Import: @slices.sh/auth/headless

Capability: organizations

```tsx
GateProps
```

Alternate import: Organization.Active from @slices.sh/auth/headless/organization

Source: @slices.sh/auth/src/headless/organization/active.tsx
