Skip to content

Component, Directive & Composables

Initialization options

ts
app.use(FeatureToggles, {
  // Static flag values (boolean or variant string)
  flags: { newDashboard: true, checkoutFlow: 'v2' },

  // Async loader — fetches flags from a backend
  loader: async () => {
    const res = await fetch('/api/feature-flags')
    return res.json()
  },

  // Poll interval for the loader in ms (default: 0 = disabled)
  reloadInterval: 60_000,

  // Allow ?feature:flagName=true in the URL (default: true in dev, false in prod)
  urlOverrides: true,

  // URL param prefix (default: 'feature')
  urlPrefix: 'feature',

  // Value returned for unknown flags (default: false)
  defaultValue: false,

  // Variables scoped to a flag
  variables: {
    newCheckout: { maxItems: 5, theme: 'dark' },
  },

  // Named flag groups
  groups: {
    beta: ['betaSearch', 'newDashboard'],
    maintenance: ['maintenanceMode', 'readOnlyBanner'],
  },

  // Dependency enforcement: if a required flag is off, the dependent is forced off too
  dependencies: {
    aiSuggestions: ['newSearch'],
  },

  // Contextual rules — evaluated reactively, priority below setFlag/URL
  rules: {
    darkMode: () => window.matchMedia('(prefers-color-scheme: dark)').matches,
  },

  // Flag metadata for DevTools and CLI
  meta: {
    newDashboard: {
      description: 'New UI',
      owner: 'alice',
      addedAt: '2025-03-01',
      ticket: 'PROJ-42',
    },
  },

  // Automatic expiry dates — after this date the flag is treated as expired
  expiry: {
    christmasBanner: '2025-01-10',
  },

  // Live updates from the server (SSE or WebSocket)
  liveUpdates: {
    type: 'sse',
    url: '/api/flags/stream',
  },

  // Server-side flag snapshot to prevent hydration mismatch
  ssrState: window.__FEATURE_FLAGS__,
})

<Feature> component

vue
<!-- Basic -->
<Feature name="newDashboard">
  <NewDashboard />
</Feature>

<!-- Fallback slot -->
<Feature name="betaSearch">
  <template #default><BetaSearchBar /></template>
  <template #fallback><LegacySearchBar /></template>
</Feature>

<!-- Fallback prop -->
<Feature name="betaSearch" fallback="Feature is under development">
  <BetaSearchBar />
</Feature>

<!-- Inverted — show when flag is off -->
<Feature name="maintenanceMode" :inverted="true">
  <MainContent />
</Feature>

<!-- Wrap in an HTML element -->
<Feature name="newDashboard" tag="section">
  <NewDashboard />
</Feature>

<!-- Loading state while loader runs -->
<Feature name="loaderFlag">
  <template #loading><Spinner /></template>
  <template #default><NewFeature /></template>
  <template #fallback><OldFeature /></template>
</Feature>

<!-- Group — show when ALL flags in the group are enabled -->
<Feature group="beta">
  <BetaLabel />
</Feature>

Props

PropTypeDefaultDescription
namestringFlag name
groupstringGroup name (alternative to name)
fallbackstring | ComponentnullWhat to render when the flag is off
invertedbooleanfalseRender when the flag is false
tagstringWrap content in an HTML element (no wrapper by default)

Slots

SlotDescription
defaultContent when the flag is on
fallbackContent when the flag is off
loadingContent while flags are loading via loader

v-feature directive

vue
<!-- Show when flag is on -->
<div v-feature="'newDashboard'">...</div>

<!-- Show when flag is off (inverted) -->
<div v-feature:not="'betaSearch'">...</div>

<!-- Show when ALL flags are on -->
<div v-feature="['newDashboard', 'betaSearch']">...</div>

Works like v-show (toggles display: none) — the DOM node is always present. For v-if-like behavior use <Feature>.

useFeature

ts
import { useFeature } from 'vue-feature-toggles'

// Single flag → Ref<boolean>
const isNewDashboard = useFeature('newDashboard')

// Multiple flags → Record<string, Ref<boolean>>
const { newDashboard, betaSearch } = useFeature(['newDashboard', 'betaSearch'])

// AND check across multiple flags → Ref<boolean>
const allEnabled = useFeature('newDashboard', 'betaSearch')

Multivariate flags & <FeatureVariant>

Flags can hold a string variant instead of a boolean — useful for A/B tests and multi-step rollouts.

ts
app.use(FeatureToggles, {
  flags: { checkoutFlow: 'v2' },
})
ts
import { useFeatureVariant } from 'vue-feature-toggles'

const variant = useFeatureVariant('checkoutFlow') // Ref<string>
vue
<FeatureVariant name="checkoutFlow">
  <template #v1><CheckoutV1 /></template>
  <template #v2><CheckoutV2 /></template>
  <template #fallback><CheckoutLegacy /></template>
</FeatureVariant>

URL overrides work identically: ?feature:checkoutFlow=v2.