Skip to main content

Client-Side Usage

Use feature flags in your Vue components with auto-imported composables.

Composables​

useToggly​

The main composable providing access to the full Toggly client.

<script setup>
const {
isReady, // Ref<boolean> - true when initial fetch completes
isLoading, // Ref<boolean> - true during any fetch
features, // Ref<Record<string, boolean>> - all feature states
error, // Ref<Error | null> - last error if any
refresh, // () => Promise<void> - manually refresh features
setIdentity, // (id: string) => Promise<void> - set user identity
destroy, // () => void - cleanup (called automatically)
} = useToggly()

// Wait for features to load
watch(isReady, (ready) => {
if (ready) {
console.log('Features loaded:', features.value)
}
})

// Set user identity after login
async function onLogin(userId: string) {
await setIdentity(userId)
}
</script>

useFeatureFlag​

Check if a single feature is enabled.

<script setup>
// Basic usage
const { isEnabled, isLoading } = useFeatureFlag('new-dashboard')

// Reactive feature check
watch(isEnabled, (enabled) => {
if (enabled) {
analytics.track('new_dashboard_shown')
}
})
</script>

<template>
<div v-if="isLoading">Loading...</div>
<NewDashboard v-else-if="isEnabled" />
<OldDashboard v-else />
</template>

useFeatureOff​

Check if a feature is disabled (inverted logic).

<script setup>
// Show content when maintenance mode is OFF
const { isEnabled: showContent } = useFeatureOff('maintenance-mode')
</script>

<template>
<MainContent v-if="showContent" />
<MaintenancePage v-else />
</template>

useFeatureGate​

Check multiple features with logical operators.

<script setup>
// All features must be enabled
const { isEnabled: hasAll } = useFeatureGate(
['feature-a', 'feature-b', 'feature-c'],
'all'
)

// Any feature enabled
const { isEnabled: hasAny } = useFeatureGate(
['premium', 'trial', 'beta-access'],
'any'
)

// Negated - show when ALL features are OFF
const { isEnabled: showFallback } = useFeatureGate(
['new-ui'],
'all',
true // negate
)
</script>

<template>
<FullExperience v-if="hasAll" />
<PartialExperience v-else-if="hasAny" />
<BasicExperience v-else />
</template>

Entity context​

Pass a page entity per composable or check — not via setIdentity. See Entity & page context.

The Nuxt client is a browser SDK: local registerContext only. It does not register schemas with the dashboard.

import { registerContext } from '@ops-ai/nuxt-toggly-core'

registerContext('Order', (order) => ({
kind: 'Order',
key: String(order.id),
attributes: { Status: order.status },
}))
<script setup>
const { isFeatureOn } = useToggly()
const order = useOrder()
const showBadge = await isFeatureOn('OrderBadge', order.value, 'Order')
</script>

Gates fail closed without entity context. setIdentity remains user only.

User Identity​

Set user identity for percentage-based rollouts and user targeting.

Pass groups and claims at client init (see Configuration). Runtime setIdentity updates identity only — it does not change groups or claims.

Setting Identity​

<script setup>
const { setIdentity } = useToggly()

// After user authentication
onMounted(async () => {
const user = await getCurrentUser()
if (user) {
await setIdentity(user.id)
}
})

// On login
async function handleLogin(credentials) {
const user = await login(credentials)
await setIdentity(user.id)
}

// On logout - clear identity
async function handleLogout() {
await setIdentity('')
}
</script>

Persistent Identity​

Identity is persisted to localStorage by default (configurable):

nuxt.config.ts
export default defineNuxtConfig({
toggly: {
persistIdentity: true, // default
},
})

Refreshing Features​

Features auto-refresh based on the refreshInterval config. You can also refresh manually:

<script setup>
const { refresh, isLoading } = useToggly()

async function forceRefresh() {
await refresh()
}
</script>

<template>
<button @click="forceRefresh" :disabled="isLoading">
Refresh Features
</button>
</template>

Error Handling​

<script setup>
const { error, isReady } = useToggly()

watch(error, (err) => {
if (err) {
console.error('Toggly error:', err)
// Features keep last-known-good values when available, then fall back to defaults
}
})
</script>

<template>
<div v-if="error" class="error-banner">
Feature service unavailable. Using cached values.
</div>
</template>

For callback-based reporting with the direct client and the shared fallback contract, see Reliability and Error Handling.

SSR Considerations​

The SDK handles SSR automatically:

  1. Server: Features fetched and cached server-side
  2. Hydration: Client receives server state, no flash
  3. Client: Takes over with reactive updates
<script setup>
const { isReady, isEnabled } = useFeatureFlag('my-feature')

// isReady is true immediately on client if SSR provided data
// No loading flash on hydration
</script>

Disable SSR for Specific Features​

For client-only features, use ClientOnly:

<template>
<ClientOnly>
<Feature feature-key="client-only-feature">
<ClientOnlyComponent />
</Feature>
</ClientOnly>
</template>

Offline Support​

Enable localStorage persistence for offline access:

nuxt.config.ts
export default defineNuxtConfig({
toggly: {
persistFeatures: true, // Cache features locally
},
})

When the API is unavailable, the SDK will:

  1. Use cached features from localStorage
  2. Fall back to featureDefaults if no cache
  3. Retry on next refresh interval

TypeScript​

All composables are fully typed:

import type { UseFeatureFlagReturn, UseTogglyReturn } from '@ops-ai/nuxt-toggly'

const flag: UseFeatureFlagReturn = useFeatureFlag('my-feature')
const toggly: UseTogglyReturn = useToggly()

See also​