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 |
|---|---|---|
PostHogFeatureAdapter | @vuetify/v0/features/adapters/posthog | PostHog↗ integration |
FlagsmithFeatureAdapter | @vuetify/v0/features/adapters/flagsmith | Flagsmith↗ integration |
LaunchDarklyFeatureAdapter | @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 { FlagsmithFeatureAdapter } from '@vuetify/v0/features/adapters/flagsmith'
app.use(createFeaturesPlugin({
adapter: new FlagsmithFeatureAdapter(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 { LaunchDarklyFeatureAdapter } 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 LaunchDarklyFeatureAdapter(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 { PostHogFeatureAdapter } from '@vuetify/v0/features/adapters/posthog'
posthog.init('<YOUR_PROJECT_API_KEY>', { api_host: 'https://app.posthog.com' })
app.use(createFeaturesPlugin({
adapter: new PostHogFeatureAdapter(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 { FlagsmithFeatureAdapter } from '@vuetify/v0/features/adapters/flagsmith'
import { PostHogFeatureAdapter } from '@vuetify/v0/features/adapters/posthog'
app.use(createFeaturesPlugin({
adapter: [
new FlagsmithFeatureAdapter(flagsmith, options),
new PostHogFeatureAdapter(posthog),
]
}))Custom Adapters
Create custom adapters by implementing the FeaturesAdapterInterface.
import type { FeaturesAdapterInterface, FeaturesAdapterFlags } from '@vuetify/v0'
class WindowFeaturesAdapter implements FeaturesAdapterInterface {
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 Interface
The adapter pattern decouples feature flags from the underlying provider.
interface FeaturesAdapterInterface {
/**
* Initialize the adapter and return initial flags.
*
* @param onUpdate Callback invoked when flags change.
* @returns Initial feature flags.
*/
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 Flag Panel
Toggle boolean and variation feature flags at runtime, using ticket isSelected, select(), unselect(), and variation() to read and control which features are active.
0 / 1 features enabled
Variation lookup
Functions
createFeatures
(_options?: FeatureOptions) => FeatureContext<FeatureTicketInput, FeatureTicket<FeatureTicketInput>>Creates a new features instance.
createFeaturesContext
<_E>(_options?: FeaturePluginOptions | undefined) => ContextTrinity<_E>createFeaturesPlugin
(_options?: FeaturePluginOptions | undefined) => PluginuseFeatures
<_E>(namespace?: string) => _EOptions
Properties
selectedValues
ComputedRef<Set<E["value"] extends Ref<infer U, infer U> ? U : E["value"]>>Computed Set of selected ticket values
selectedIndexes
ComputedRef<Set<number>>Methods
move
(id: ID, toIndex: number) => E | undefinedSeek for a ticket based on direction and optional predicate
seek
(direction?: "first" | "last", from?: number, predicate?: (ticket) => boolean) => E | undefinedon
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidListen for registry events
off
<K extends Extensible<RegistryEventName>>(event: K, cb: EventHandler<E, K>) => voidStop listening for registry events
emit
<K extends Extensible<RegistryEventName>>(event: K, data: EventPayload<E, K>) => voidEmit an event with data
batch
<R>(fn: () => R) => RExecute operations in a batch, deferring cache invalidation and event emission until complete
variation
(id: ID, fallback?: unknown) => unknownGet the variation value of a feature, or a fallback if not set.
register
(registration?: Partial<Z>) => ERegister a feature (accepts input type, returns output type)