@presage-kit/vue
Vue 3 bindings for Presage. Provides a plugin for dependency injection and composables for reactive adaptation.
pnpm add @presage-kit/core @presage-kit/vueAdaptivePlugin
Section titled “AdaptivePlugin”A Vue 3 plugin that provides the AdaptiveClient to all components via provide/inject.
import { createApp } from 'vue'import { AdaptivePlugin } from '@presage-kit/vue'import { createAdaptiveClient } from '@presage-kit/core'
const client = createAdaptiveClient({ /* ... */ })
const app = createApp(App)app.use(AdaptivePlugin, { client })app.mount('#app')Install options: AdaptivePluginOptions
interface AdaptivePluginOptions { client: AdaptiveClient}| Option | Type | Required | Description |
|---|---|---|---|
client | AdaptiveClient | Yes | Client from createAdaptiveClient() |
Implementation: Calls app.provide() with an injection key symbol, making the client available to all descendant components.
useAdaptive(adaptationId, config)
Section titled “useAdaptive(adaptationId, config)”Resolves an adaptation point reactively. Re-evaluates when user context changes.
import { useAdaptive } from '@presage-kit/vue'
const { selectedVariant, resolution, context, track } = useAdaptive('onboarding', { variants: ['guided-tour', 'standard', 'minimal'] as const, defaultVariant: 'standard',})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:
The returned object uses JavaScript getters backed by Vue computed() refs, making all values reactive.
| Field | Type | Description |
|---|---|---|
selectedVariant | V (getter) | Currently selected variant |
resolution | ResolvedAdaptation (getter) | Full resolution metadata |
context | UserContext (getter) | Current user context |
track | (event: string, props?: Record<string, unknown>) => void | Scoped track function |
Reactivity: The composable uses useAtom() internally to bridge the core’s atom-based state to Vue’s reactivity system. When the client state changes, all computed values update automatically.
Impressions: Uses Vue’s watch() with { immediate: true } to track presage:impression events when the selected variant changes.
Usage in templates:
<script setup lang="ts">import { useAdaptive } from '@presage-kit/vue'
const { selectedVariant } = useAdaptive('panel', { variants: ['compact', 'expanded'] as const, defaultVariant: 'compact',})</script>
<template> <CompactPanel v-if="selectedVariant === 'compact'" /> <ExpandedPanel v-else /></template>useVariant(adaptationId, config)
Section titled “useVariant(adaptationId, config)”Lightweight composable returning only the selected variant string.
import { useVariant } from '@presage-kit/vue'
const variant = useVariant('layout', { variants: ['sidebar', 'topnav'] as const, defaultVariant: 'sidebar',})Parameters: Same as useAdaptive().
Return type: V — The selected variant string (reactive getter).
Internally delegates to useAdaptive() and returns selectedVariant.
Usage in templates:
<script setup lang="ts">import { useVariant } from '@presage-kit/vue'
const variant = useVariant('cta-style', { variants: ['primary', 'secondary'] as const, defaultVariant: 'primary',})</script>
<template> <button :class="`btn btn--${variant}`">Get Started</button></template>useAdaptiveClient()
Section titled “useAdaptiveClient()”Returns the AdaptiveClient instance from the plugin injection.
import { useAdaptiveClient } from '@presage-kit/vue'
const client = useAdaptiveClient()
client.track('feature_used', { featureId: 'export' })client.identify('user-789', { role: 'admin' })const context = client.getContext()Return type: AdaptiveClient
Throws: Error if AdaptivePlugin has not been installed.
Common patterns:
<script setup lang="ts">import { useAdaptiveClient } from '@presage-kit/vue'
const client = useAdaptiveClient()
// Identify after authenticationonMounted(() => { const user = getCurrentUser() client.identify(user.id, { role: user.role, plan: user.plan, signupDate: user.createdAt, })})
// Track actionsfunction handleExport() { client.track('feature_used', { featureId: 'export' }) doExport()}
// Evaluate rules imperativelyfunction getNavAction() { return client.evaluateAction('sidebar-nav')}</script>Differences from React Adapter
Section titled “Differences from React Adapter”| Feature | React | Vue |
|---|---|---|
| Provider | <AdaptiveProvider> component | AdaptivePlugin (Vue plugin) |
| Declarative component | <Adaptive> + <Variant> | Not included (use v-if with useAdaptive()) |
| Adaptive navigation | <AdaptiveNav> component | Manual with evaluateAction() |
| Hook/composable return | Plain object | Object with reactive getters |
| State bridge | useSyncExternalStore-style | ref + atom subscribe() |
The Vue adapter is intentionally leaner. Vue’s template syntax and reactivity system make it natural to use v-if/v-else with the composable return value, removing the need for wrapper components like <Adaptive>.