Skip to main content
Vuetify0 v1.0 is here
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

createPlugin

Factory for creating Vue plugins with typed dependency injection and lifecycle hooks.

Edit this page
Report a Bug
Open issues
View on GitHub
Copy Markdown

StableAdvancedJun 29, 2026

Usage

For most cases, use createPluginContext — it generates the full plugin tuple from a factory function:

ts
import { createPluginContext } from '@vuetify/v0'

interface AnalyticsOptions {
  trackPageviews?: boolean
}

interface AnalyticsContext {
  track: (event: string) => void
}

export const [createAnalyticsContext, createAnalyticsPlugin, useAnalytics] =
  createPluginContext<AnalyticsOptions, AnalyticsContext>(
    'my:analytics',
    (options) => ({
      track: (event) => {
        if (options.trackPageviews) console.log(event)
      },
    }),
  )
src/main.ts
app.use(createAnalyticsPlugin({ trackPageviews: true }))
src/components/MyComponent.vue
<script setup lang="ts">
  import { useAnalytics } from './plugins/analytics'

  const analytics = useAnalytics()
  analytics.track('page_view')
</script>

Architecture

createPlugin wraps createContext for Vue plugin registration:

Plugin Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Plugin Architecture

Low-level API

Use createPlugin directly when you need fine-grained control over plugin setup, or when composing with existing createContext instances:

ts
import { createContext, createPlugin } from '@vuetify/v0'

interface MyPluginContext {
  app: string
}

export const [useMyContext, provideMyContext] = createContext<MyPluginContext>('provide-namespace')

export function createMyPlugin () {
  const context = {
    app: 'my-app'
  }

  return createPlugin({
    namespace: 'provide-namespace',
    provide: (app: App) => {
      provideMyContext(context, app)
    },
    setup: (app: App) => {
      // For everything else not provide related
    }
  })
}
Tip

The setup and provide hooks are separated for semantic purposes — provide is for DI context, setup is for side effects (watchers, adapters, globals).

Examples

Dashboard Features

A four-file plugin example showing how createPlugin, createContext, and createGroup compose to manage feature-flag state for a dashboard. plugin.ts is the factory: it calls createGroup(), bulk-registers five feature toggles with onboard(), pre-selects two via group.select(['animations', 'notifications']), assembles a DashboardContext object (app name, locale ref, locales list, and the group instance), and calls provideDashboard(context) through the [useDashboard, provideDashboard] tuple produced by createContext. A commented-out block shows how the same code would be wrapped in createPlugin() for app.use() in a real app — for sandbox purposes the factory returns the context object directly.

DashboardProvider.vue creates the plugin instance and calls provideContext in a single setup call, then renders only a slot. DashboardConsumer.vue destructures { group, locale, locales, app } from useDashboard() and renders a feature grid — each feature is a ticket with toggle(), isSelected, and value — alongside a locale selector that writes directly to context.locale. The critical pattern: the consumer never imports from the provider; it only imports from plugin.ts. dashboard.vue composes the two.

The example illustrates the primary reason to compose createGroup inside a plugin rather than manage selection state ad hoc: the group handles toggle logic, mandatory enforcement, select-all, and unselect-all without any custom bookkeeping. The plugin is the factory; the group is the logic layer; the context is the contract. For plugin contexts that need persistence across page reloads, see the Persistence section.

Plugin Architecture

Use controls to zoom and pan. Click outside or press Escape to close.

Plugin Architecture

File breakdown:

FileRole
plugin.tsDefines the DashboardContext (wrapping a GroupContext), creates the context tuple, and exports the createDashboardPlugin factory
DashboardProvider.vueCreates the plugin instance and provides the context, rendering only a slot
DashboardConsumer.vueConsumes the context via useDashboard() and uses the group’s toggle(), selectAll(), and unselectAll() methods
dashboard.vueEntry point that composes Provider around Consumer

Key patterns:

  • Provider components are invisible wrappers that render only a slot

  • The plugin composes createGroup — each feature is a ticket with selection state built in

  • In a real app, the factory would return a plugin for app.use() — here it returns context directly for the sandbox

  • Consumers import only from plugin.ts, never from the Provider

My Dashboard

2 / 5 features enabled

Active features

AnimationsNotifications

Recipes

Persistence

Plugins can automatically save and restore state across page reloads using useStorage. Add persist and restore hooks to the plugin config, then consumers opt in with persist: true.

Plugin author

Define what to save and how to restore in the createPluginContext config:

ts
import { createPluginContext } from '@vuetify/v0'

export const [createThemeContext, createThemePlugin, useTheme] =
  createPluginContext('v0:theme', createTheme, {
    setup: (context, app, options) => {
      // adapter setup...
    },
    // Return the value to save — called reactively
    persist: ctx => ctx.selectedId.value,
    // Apply saved value on load — called before setup
    restore: (ctx, saved) => ctx.select(saved),
  })

Consumer

ts
app.use(createThemePlugin({ persist: true }))

When persist: true is passed, the plugin automatically:

  1. Reads from useStorage using the plugin namespace as key

  2. Calls restore with the saved value before setup runs

  3. Watches the persist return value and writes changes to storage

Tip

The default option becomes the true default — it’s only used when no persisted value exists.

Lifecycle

Persist Lifecycle

Use controls to zoom and pan. Click outside or press Escape to close.

Persist Lifecycle

The critical ordering is restore before setup. This means adapters (like the theme CSS variable injector) see the correct restored state on their first run — no flash of wrong values.

Hook signatures

ts
interface PluginContextConfig<O, E> {
  /** Return the value to persist — called reactively inside a watch source */
  persist?: (context: E) => unknown
  /** Restore previously persisted state — called before setup */
  restore?: (context: E, saved: unknown) => void
}

The persist return value is stored under the plugin namespace key (e.g. v0:theme). restore receives whatever was stored — cast to the expected type inside the hook.

Built-in support

PluginPersistsStorage key
createThemePluginSelected theme IDv0:theme
createRtlPluginRTL directionv0:rtl
createLocalePluginSelected localev0:locale

FAQ

Discord
Need help? Join our community for support and discussions ↗

API Reference

The following API details are for the createPlugin composable.
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/