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

# Feature gates

> Render UI from entitlement, usage, and plan state supplied by your authenticated backend.

Gate components are presentational. They never fetch customer data and never receive a customer ID. Load entitlement, usage, and plan state through your authenticated backend, then pass the result into the gate.

<img src="https://mintcdn.com/nozle-d78f01d8/BqSeIMueV970shtJ/images/react-sdk/gates.png?fit=max&auto=format&n=BqSeIMueV970shtJ&q=85&s=75a1fc9f6345deed27fc4b50f148290c" alt="Feature gates and upgrade prompt" width="1400" height="820" data-path="images/react-sdk/gates.png" />

## `FeatureGate`

Renders `children` when `allowed` is true, `fallback` when it is false, and `null` while `loading` is true.

```tsx theme={null}
import { FeatureGate, UpgradePrompt } from '@nozle-js/react'

<FeatureGate
  allowed={entitlement.allowed}
  loading={entitlement.loading}
  fallback={<UpgradePrompt planName="Growth" />}
>
  <AnalyticsDashboard />
</FeatureGate>
```

| Prop       | Type        | Default  | Description                                |
| ---------- | ----------- | -------- | ------------------------------------------ |
| `allowed`  | `boolean`   | required | Whether children may render.               |
| `loading`  | `boolean`   | `false`  | Returns `null` while customer state loads. |
| `fallback` | `ReactNode` | `null`   | Rendered when access is denied.            |
| `children` | `ReactNode` | required | Protected content.                         |

## `UsageGate`

Renders children while `usage < limit`. Equality is treated as exhausted.

```tsx theme={null}
<UsageGate
  usage={8_200}
  limit={10_000}
  fallback={<span>Monthly limit reached</span>}
>
  <ApiCallForm />
</UsageGate>
```

| Prop       | Type        | Default  | Description                                   |
| ---------- | ----------- | -------- | --------------------------------------------- |
| `usage`    | `number`    | required | Current usage.                                |
| `limit`    | `number`    | required | Usage ceiling.                                |
| `fallback` | `ReactNode` | `null`   | Rendered when usage is at or above the limit. |
| `children` | `ReactNode` | required | Content available below the limit.            |

## `PlanGate`

Checks whether `currentPlan` is included in `allowedPlans`.

```tsx theme={null}
<PlanGate
  currentPlan={billing.planCode}
  allowedPlans={['growth', 'scale']}
  fallback={<UpgradePrompt planName="Growth" />}
>
  <AdvancedSettings />
</PlanGate>
```

| Prop           | Type        | Default  | Description                                |
| -------------- | ----------- | -------- | ------------------------------------------ |
| `currentPlan`  | `string`    | required | Current plan identifier.                   |
| `allowedPlans` | `string[]`  | required | Plans that may render children.            |
| `fallback`     | `ReactNode` | `null`   | Rendered for a plan outside the allowlist. |
| `children`     | `ReactNode` | required | Plan-gated content.                        |

## `UpgradePrompt`

Displays an upgrade message and button. Without `onUpgrade`, the button navigates to `/upgrade`.

```tsx theme={null}
<UpgradePrompt
  planName="Scale"
  onUpgrade={() => router.push('/settings/billing')}
/>
```

| Prop        | Type         | Default                          | Description                                           |
| ----------- | ------------ | -------------------------------- | ----------------------------------------------------- |
| `text`      | `string`     | `Upgrade to access this feature` | Message used when `planName` is absent.               |
| `planName`  | `string`     | —                                | Produces “Upgrade to \[plan] to access this feature.” |
| `onUpgrade` | `() => void` | Navigate to `/upgrade`           | Upgrade action.                                       |

## `LockedOverlay`

Shows an upgrade prompt over blurred, non-interactive content when `locked` is true. When unlocked, it returns the children without a wrapper.

```tsx theme={null}
<LockedOverlay
  locked={!entitlement.allowed}
  upgradePlanName="Scale"
  onUpgrade={() => setUpgradeOpen(true)}
>
  <AnalyticsPreview />
</LockedOverlay>
```

| Prop              | Type         | Default                | Description                          |
| ----------------- | ------------ | ---------------------- | ------------------------------------ |
| `locked`          | `boolean`    | required               | Enables the blur and overlay.        |
| `upgradeText`     | `string`     | —                      | Custom prompt text.                  |
| `upgradePlanName` | `string`     | —                      | Plan name passed to `UpgradePrompt`. |
| `onUpgrade`       | `() => void` | Navigate to `/upgrade` | Upgrade action.                      |
| `children`        | `ReactNode`  | required               | Preview content.                     |

## Backend-driven composition

```tsx theme={null}
function ReportingSection() {
  const { data, loading } = useMerchantBillingState()

  return (
    <FeatureGate
      allowed={data?.entitlements.reporting ?? false}
      loading={loading}
      fallback={<UpgradePrompt planName="Growth" />}
    >
      <PlanGate
        currentPlan={data?.planCode ?? ''}
        allowedPlans={['growth', 'scale', 'enterprise']}
      >
        <UsageGate
          usage={data?.usage.reports ?? 0}
          limit={data?.limits.reports ?? 0}
          fallback={<span>Report limit reached</span>}
        >
          <ReportBuilder />
        </UsageGate>
      </PlanGate>
    </FeatureGate>
  )
}
```

<Warning>
  Gates improve the user interface; they are not an authorization boundary. Enforce entitlement and usage rules again on the server before performing protected work.
</Warning>
