Skip to content

@presage-kit/react

React bindings for Presage. Provides a context provider, declarative components, and hooks.

Terminal window
pnpm add @presage-kit/core @presage-kit/react

Provides the AdaptiveClient to descendant components via React context.

import { AdaptiveProvider } from '@presage-kit/react'
<AdaptiveProvider client={client}>
<App />
</AdaptiveProvider>

Props:

PropTypeRequiredDescription
clientAdaptiveClientYesClient from createAdaptiveClient()
childrenReactNodeYesComponent tree

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:

PropTypeRequiredDescription
idstringYesAdaptation point identifier
defaultVariantstringYesFallback variant ID
childrenReactNodeYesMust 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 null if no variant matches (shouldn’t happen with defaultVariant)

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:

PropTypeRequiredDescription
idstringYesVariant identifier (referenced in rule actions)
childrenReactNodeYesContent to render when selected

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:

PropTypeRequiredDescription
idstringYesAdaptation point identifier
itemsT[]YesArray of items extending NavItem
renderItem(item: T, index: number) => ReactNodeYesRender 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' } — Returns null (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>
)}
/>

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:

ParamTypeDescription
adaptationIdstringUnique adaptation point ID
config.variantsreadonly V[]Array of variant IDs
config.defaultVariantNoInfer<V>Default variant (must be in variants)
config.strategyStrategyOptional. Defaults to { type: 'rules' }

Return type: UseAdaptiveResult<V>

FieldTypeDescription
selectedVariantVCurrently selected variant
resolutionResolvedAdaptationFull resolution metadata
contextUserContextCurrent user context
track(event: string, props?: Record<string, unknown>) => voidTrack 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'

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.

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>.