@presage-kit/react
React bindings for Presage. Provides a context provider, declarative components, and hooks.
pnpm add @presage-kit/core @presage-kit/react<AdaptiveProvider>
Section titled “<AdaptiveProvider>”Provides the AdaptiveClient to descendant components via React context.
import { AdaptiveProvider } from '@presage-kit/react'
<AdaptiveProvider client={client}> <App /></AdaptiveProvider>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
client | AdaptiveClient | Yes | Client from createAdaptiveClient() |
children | ReactNode | Yes | Component tree |
<Adaptive>
Section titled “<Adaptive>”Declares an adaptation point. Evaluates rules and renders the matching <Variant> child.
import { Adaptive, Variant } from '@presage-kit/react'
<Adaptive id="onboarding" defaultVariant="standard"> <Variant id="guided-tour"><GuidedTour /></Variant> <Variant id="standard"><StandardView /></Variant></Adaptive>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Adaptation point identifier |
defaultVariant | string | Yes | Fallback variant ID |
children | ReactNode | Yes | Must contain <Variant> elements |
Behavior:
- Extracts
<Variant>children and their IDs - Calls
useAdaptive()internally with the extracted variant list - Renders the content of the matching
<Variant> - Returns
nullif no variant matches (shouldn’t happen withdefaultVariant)
<Variant>
Section titled “<Variant>”Declares a variant within an <Adaptive> block. Does not render anything on its own — <Adaptive> controls which variant is visible.
<Variant id="guided-tour"> <GuidedTour /></Variant>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Variant identifier (referenced in rule actions) |
children | ReactNode | Yes | Content to render when selected |
<AdaptiveNav>
Section titled “<AdaptiveNav>”Renders navigation items with adaptive reordering.
import { AdaptiveNav, type NavItem } from '@presage-kit/react'
<AdaptiveNav<MenuItem> id="sidebar" items={menuItems} renderItem={(item, index) => <NavLink key={item.id} item={item} />}/>Props:
| Prop | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Adaptation point identifier |
items | T[] | Yes | Array of items extending NavItem |
renderItem | (item: T, index: number) => ReactNode | Yes | Render function per item |
NavItem interface:
interface NavItem { id: string [key: string]: unknown}Action handling:
{ type: 'reorder', order: [...] }— Reorders items to match the order array. Items not in the array are appended at the end.{ type: 'hide' }— Returnsnull(hides the entire navigation).- Other actions or no match — Renders items in their original order.
Generics: AdaptiveNav is generic over the item type:
interface MenuItem extends NavItem { label: string href: string icon: React.ReactNode}
<AdaptiveNav<MenuItem> id="sidebar" items={menuItems} renderItem={(item) => ( <a href={item.href}>{item.icon} {item.label}</a> )}/>useAdaptive(adaptationId, config)
Section titled “useAdaptive(adaptationId, config)”Resolves an adaptation point and tracks impressions.
import { useAdaptive } from '@presage-kit/react'
const { selectedVariant, resolution, context, track } = useAdaptive('feature-panel', { variants: ['compact', 'expanded', 'hidden'] as const, defaultVariant: 'compact',})Parameters:
| Param | Type | Description |
|---|---|---|
adaptationId | string | Unique adaptation point ID |
config.variants | readonly V[] | Array of variant IDs |
config.defaultVariant | NoInfer<V> | Default variant (must be in variants) |
config.strategy | Strategy | Optional. Defaults to { type: 'rules' } |
Return type: UseAdaptiveResult<V>
| Field | Type | Description |
|---|---|---|
selectedVariant | V | Currently selected variant |
resolution | ResolvedAdaptation | Full resolution metadata |
context | UserContext | Current user context |
track | (event: string, props?: Record<string, unknown>) => void | Track function that auto-attaches _adaptationId |
Impressions: Automatically tracks presage:impression when selectedVariant changes, with properties:
{ adaptationId: string variant: string strategy: string}TypeScript: Uses NoInfer<V> to prevent defaultVariant from widening the type. Use as const on the variants array for best type inference:
const { selectedVariant } = useAdaptive('x', { variants: ['a', 'b', 'c'] as const, defaultVariant: 'a',})// selectedVariant: 'a' | 'b' | 'c'useVariant(adaptationId, config)
Section titled “useVariant(adaptationId, config)”Lightweight hook returning only the selected variant string.
import { useVariant } from '@presage-kit/react'
const variant = useVariant('layout', { variants: ['sidebar', 'topnav'] as const, defaultVariant: 'sidebar',})// variant: 'sidebar' | 'topnav'Parameters: Same as useAdaptive().
Return type: V — The selected variant string.
Internally delegates to useAdaptive() and destructures selectedVariant.
useAdaptiveClient()
Section titled “useAdaptiveClient()”Returns the AdaptiveClient from context.
import { useAdaptiveClient } from '@presage-kit/react'
const client = useAdaptiveClient()
client.track('button_clicked', { buttonId: 'cta' })client.identify('user-456', { role: 'editor' })const ctx = client.getContext()Return type: AdaptiveClient
Throws: Error if called outside <AdaptiveProvider>.