createPlugin
Register app-wide plugins with typed context any component can consume. Prefer createPluginContext unless you need to control provide and setup yourself.
Usage
For most cases, use createPluginContext — it generates the full plugin tuple from a factory function:
import { createApp } from 'vue'
import { createAnalyticsPlugin } from './plugins/analytics'
import App from './App.vue'
const app = createApp(App)
app.use(createAnalyticsPlugin({ trackPageviews: true }))
app.mount('#app')<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:
Low-level API
Use createPlugin directly when you need fine-grained control over plugin setup, or when composing with existing createContext instances:
The setup and provide hooks are separated for semantic purposes — provide is for DI context, setup is for side effects (watchers, adapters, globals).
Vue DevTools
Opt a plugin into the v0 inspector in Vue DevTools with { devtools: true }. Off by default.
The inspector shows that plugin’s context — refs and class getters unwrapped, functions omitted. Pass inspect to overlay extra keys (adapter names, values behind methods) without replacing the rest of the snapshot.
import { createLogger, createPluginContext } from '@vuetify/v0'
export const [createLoggerContext, createLoggerPlugin, useLogger] =
createPluginContext('v0:logger', createLogger, {
inspect: ctx => ({
level: ctx.current(),
enabled: ctx.enabled(),
}),
})import { createApp } from 'vue'
import { createLocalePlugin, createThemePlugin } from '@vuetify/v0'
import App from './App.vue'
const app = createApp(App)
app.use(createThemePlugin({ devtools: true }))
app.use(createLocalePlugin()) // not in the inspector
app.mount('#app')Plugin authors can default it on via createPluginContext config (devtools: true); the install-time option overrides.
createPluginContext binds the context for you. Plugins that wrap createPlugin directly must call bindPluginContext from provide, or the inspector shows context: undefined:
import { bindPluginContext, createContext, createPlugin } from '@vuetify/v0'
import type { App } from 'vue'
const [useMyContext, provideMyContext] = createContext<{ ready: boolean }>('v0:my-plugin')
export function createMyPlugin () {
const context = { ready: true }
const namespace = 'v0:my-plugin'
return createPlugin({
namespace,
devtools: true,
provide: (app: App) => {
provideMyContext(context, app)
bindPluginContext(app, namespace, context)
},
})
}This is __DEV__-gated and a no-op if @vue/devtools-api is not present. Pair it with vite-plugin-vue-devtools (or the browser extension) so the inspector has a host.
Examples
My Dashboard
2 / 5 features enabled
Active features
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:
import { createPluginContext, createTheme } from '@vuetify/v0'
export const [createThemeContext, createThemePlugin, useTheme] =
createPluginContext('v0:theme', createTheme, {
setup: (context, app, options) => {
// adapter setup...
},
persist: ctx => ctx.selectedId.value,
restore: (ctx, saved) => ctx.select(saved),
})Consumer
import { createApp } from 'vue'
import { createThemePlugin } from '@vuetify/v0'
import App from './App.vue'
const app = createApp(App)
app.use(createThemePlugin({ persist: true }))
app.mount('#app')When persist: true is passed, the plugin automatically:
Reads from
useStorageusing the plugin namespace as keyCalls
restorewith the saved value beforesetuprunsWatches the
persistreturn value and writes changes to storage
The default option becomes the true default — it’s only used when no persisted value exists.
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
import { createPluginContext, createTheme } from '@vuetify/v0'
import type { PluginContextConfig } from '@vuetify/v0'
const hooks: PluginContextConfig<unknown, ReturnType<typeof createTheme>> = {
persist: ctx => ctx.selectedId.value,
restore: (ctx, saved) => ctx.select(saved as string),
}
createPluginContext('v0:theme', createTheme, hooks)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
| Plugin | Persists | Storage key |
|---|---|---|
createThemePlugin | Selected theme ID | v0:theme |
createRtlPlugin | RTL direction | v0:rtl |
createLocalePlugin | Selected locale | v0:locale |
FAQ
createPluginContext generates the full [createXContext, createXPlugin, useX] tuple from a factory function — use it for most plugins. Drop to createPlugin directly only when you need fine-grained control over setup, or are composing with an existing createContext instance.
provide is for DI context — it calls your provideXContext(). setup is for everything else: side effects like watchers, adapters, and globals. They’re separated for semantic clarity.
Add persist and restore hooks to the plugin config and have consumers opt in with persist: true. The plugin reads and writes through useStorage under the plugin namespace, calling restore with the saved value before setup runs so adapters never flash wrong values.
With persist: true, a previously persisted value wins on load — default is only used when no persisted value exists yet. restore runs before setup and applies the saved value, so default is the true fallback, not an override.