useFeatures
Manage feature flags and variations across your application.
Installation
Install the Features plugin in your app’s entry point:
import { createApp } from 'vue'
import { createFeaturesPlugin } from '@vuetify/v0'
import App from './App.vue'
const app = createApp(App)
app.use(
createFeaturesPlugin({
features: {
analytics: true,
debug_mode: false,
notifications: false,
search: { $value: true, $variation: 'v2' },
},
})
)
app.mount('#app')Usage
Once the plugin is installed, access feature flags and variations in any component:
<script setup lang="ts">
import { useFeatures } from '@vuetify/v0'
const features = useFeatures()
</script>
<template>
<div>
<p>Analytics: {{ features.get('analytics') }}</p>
<p>Debug Mode: {{ features.get('debug_mode') }}</p>
<p>Notifications: {{ features.get('notifications') }}</p>
<p>Search Variation: {{ features.variation('search', 'v1') }}</p>
</div>
</template>Optionally register features at runtime:
<script setup lang="ts">
import { useFeatures } from '@vuetify/v0'
const features = useFeatures()
// Register at runtime
features.register({ id: 'beta', value: false })
// Enable/disable via selection helpers
features.select('beta')
features.unselect('analytics')
</script>Adapters
Adapters let you swap the underlying feature flag provider without changing your application code.
| Adapter | Import | Description |
|---|---|---|
PostHogFeaturesAdapter | @vuetify/v0/features/adapters/posthog | PostHog↗︎ integration |
FlagsmithFeaturesAdapter | @vuetify/v0/features/adapters/flagsmith | Flagsmith↗︎ integration |
LaunchDarklyFeaturesAdapter | @vuetify/v0/features/adapters/launchdarkly | LaunchDarkly↗︎ integration |
Flagsmith
Flagsmith↗︎ is an open-source feature flag platform. Requires the @flagsmith/flagsmith package.
pnpm add @flagsmith/flagsmithnpm install @flagsmith/flagsmithyarn add @flagsmith/flagsmithbun add @flagsmith/flagsmithimport flagsmith from '@flagsmith/flagsmith'
import { FlagsmithFeaturesAdapter } from '@vuetify/v0/features/adapters/flagsmith'
app.use(createFeaturesPlugin({
adapter: new FlagsmithFeaturesAdapter(flagsmith, {
environmentID: '<YOUR_ENV_ID>',
// ...other flagsmith options
})
}))LaunchDarkly
LaunchDarkly↗︎ is a feature management platform. Requires the launchdarkly-js-client-sdk package.
pnpm add launchdarkly-js-client-sdknpm install launchdarkly-js-client-sdkyarn add launchdarkly-js-client-sdkbun add launchdarkly-js-client-sdkimport * as LDClient from 'launchdarkly-js-client-sdk'
import { LaunchDarklyFeaturesAdapter } from '@vuetify/v0/features/adapters/launchdarkly'
const client = LDClient.initialize('<YOUR_CLIENT_SIDE_ID>', { key: 'user-key' })
await client.waitForInitialization()
app.use(createFeaturesPlugin({
adapter: new LaunchDarklyFeaturesAdapter(client)
}))PostHog
PostHog↗︎ is an open-source product analytics and feature flag platform. Requires the posthog-js package.
pnpm add posthog-jsnpm install posthog-jsyarn add posthog-jsbun add posthog-jsimport posthog from 'posthog-js'
import { PostHogFeaturesAdapter } from '@vuetify/v0/features/adapters/posthog'
posthog.init('<YOUR_PROJECT_API_KEY>', { api_host: 'https://app.posthog.com' })
app.use(createFeaturesPlugin({
adapter: new PostHogFeaturesAdapter(posthog)
}))Multiple Adapters
You can combine flags from multiple sources by passing an array of adapters. They are initialized in order, and flags are merged (last one wins for conflicting keys).
import { FlagsmithFeaturesAdapter } from '@vuetify/v0/features/adapters/flagsmith'
import { PostHogFeaturesAdapter } from '@vuetify/v0/features/adapters/posthog'
app.use(createFeaturesPlugin({
adapter: [
new FlagsmithFeaturesAdapter(flagsmith, options),
new PostHogFeaturesAdapter(posthog),
]
}))Custom Adapters
Create custom adapters by extending FeaturesAdapter.
import { FeaturesAdapter } from '@vuetify/v0'
import type { FeaturesAdapterFlags } from '@vuetify/v0'
class WindowFeaturesAdapter extends FeaturesAdapter {
setup (onUpdate: (flags: FeaturesAdapterFlags) => void): FeaturesAdapterFlags {
const update = (event: CustomEvent) => {
onUpdate(event.detail)
}
window.addEventListener('v0:update-features', update as EventListener)
this.disposeFn = () => {
window.removeEventListener('v0:update-features', update as EventListener)
}
// Return initial state if available, or empty object
return window.__INITIAL_FEATURES__ || {}
}
dispose () {
this.disposeFn()
}
private disposeFn = () => {}
}Adapter Base Class
The adapter pattern decouples feature flags from the underlying provider.
abstract class FeaturesAdapter {
/**
* Initialize the adapter and return initial flags.
*
* @param onUpdate Callback invoked when flags change.
* @returns Initial feature flags.
*/
abstract setup (onUpdate: (flags: FeaturesAdapterFlags) => void): FeaturesAdapterFlags
/**
* Cleanup adapter resources.
*/
dispose? (): void
}Architecture
useFeatures extends createGroup for multi-selection and createTokens for variations:
Reactivity
Feature flags inherit reactivity from createGroup. Selection state is reactive, but lookup methods return static values.
| Property | Reactive | Notes |
|---|---|---|
selectedIds | Set of enabled feature IDs | |
selectedItems | Computed array of enabled features | |
ticket isSelected | true when this feature is enabled | |
variation(id, fallback?) | Returns the $variation value for a feature, or fallback if unset |
Examples
Feature flags
3 / 5 onExpress checkout
Single-page checkout with saved cards
Dark storefront
Opt-in dark color scheme
Beta banner
Promo ribbon shown to early-access users
Search engine
Backend that powers product search
Product layout
How the catalog grid is presented
FAQ
useFeatures toggles capabilities on or off (with optional variations) regardless of who the user is; usePermissions answers whether a given role may perform an action on a subject. Use flags for rollout and experiments, permissions for access control.
Give the feature a $variation payload — search: { $value: true, $variation: 'v2' } — and read it with features.variation('search', 'v1'), passing a fallback for when it’s unset. Variation values are static, not reactive.
Yes. Pass an array of adapters to createFeaturesPlugin; they initialize in order and their flags merge, with the last adapter winning on conflicting keys.
Yes. features.register({ id, value }) adds a flag after install, features.select(id) / features.unselect(id) enable or disable one, and features.toggle(id) flips it. Selection state is reactive, so gated UI updates on the next tick.