> ## Documentation Index
> Fetch the complete documentation index at: https://docs.fanfare.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Slots and Render Props

> Replace specific widget states or take over the full widget rendering.

Slots let you replace specific parts of `ExperienceWidget` while keeping the default journey orchestration. Use slots when most of the widget works for you but one or two states need custom brand treatment.

## Slot example

```tsx theme={null}
import { ExperienceWidget } from "@fanfare-io/fanfare-sdk-react";

export function LaunchWidget() {
  return (
    <ExperienceWidget
      experienceId="exp_123"
      slots={{
        upcoming: ({ startsAt, canEnter, onEnter }) => (
          <section className="launch-upcoming">
            <h2>Early access opens soon</h2>
            {startsAt ? <p>Starts {startsAt.toLocaleString()}</p> : null}
            {canEnter ? (
              <button onClick={onEnter}>Notify me</button>
            ) : null}
          </section>
        ),
        granted: ({ grant }) => (
          <CheckoutButton grantToken={grant}>
            Continue to checkout
          </CheckoutButton>
        ),
      }}
    />
  );
}
```

The `granted` slot's `grant` prop is the grant **token string** (`grant?: string`), and may be `undefined`. Pass it to your checkout handoff as a token, not as an object.

## Available slots

| Slot            | Rendered when                                                                                                                                    |
| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `start`         | The journey is ready and waiting to start.                                                                                                       |
| `loading`       | The journey or a stage action is loading.                                                                                                        |
| `auth`          | Authentication is required.                                                                                                                      |
| `accessCode`    | An access code is required.                                                                                                                      |
| `challenge`     | Additional verification is required.                                                                                                             |
| `upcoming`      | The routed sequence is scheduled (not yet open); `onEnter` joins the waitlist attachment when `canEnter` is true.                                |
| `waitlist`      | The routed sequence is scheduled and the consumer has joined its waitlist attachment (`sequence.waitlist.status` is `waitlisted` or `notified`). |
| `enterable`     | The sequence is active and the consumer can enter.                                                                                               |
| `participating` | The consumer is participating.                                                                                                                   |
| `granted`       | The consumer has an active grant.                                                                                                                |
| `expired`       | A previous admission is no longer usable.                                                                                                        |
| `ended`         | The experience or sequence has a terminal outcome. Also rendered for phase `"unavailable"` (a non-terminal placeholder) for convenience.         |
| `error`         | The widget cannot continue without recovery.                                                                                                     |

Slot props include the current `snapshot`, `view`, and `error` where relevant, plus state-specific callbacks such as `onStart`, `onEnter`, `onLeave`, or `onRetry`.

Inside the `enterable` and `participating` slots the slot's `sequence` is a routed `SequenceView`; participating views expose their live data as the `display$` atom (not `state$`). Subscribe to it (for example with `useNanostore`) to render real-time fields such as queue position.

## Render prop

Use the render prop when you want the widget to create and observe the journey, but you want to own the entire UI for that widget instance.

```tsx theme={null}
<ExperienceWidget experienceId="exp_123">
  {({ view, start, isStarting, error }) => {
    if (error) return <ErrorPanel message={error} />;
    if (!view) return <LoadingPanel />;

    if (view.journeyStage === "ready") {
      return (
        <button disabled={isStarting} onClick={() => void start()}>
          Enter launch
        </button>
      );
    }

    return <CustomJourneyView view={view} />;
  }}
</ExperienceWidget>
```

If you need to share journey state across multiple components or routes, use `useExperienceJourney` directly instead of the render prop.
