Skip to main content

Overview

Factory for creating type-safe Vue dependency injection contexts. Eliminates silent failures by throwing errors when context is not found, improving developer experience over raw provide/inject. Supports both static key mode (key fixed at creation) and dynamic key mode (key provided at runtime).

Signature

// Static key mode
function createContext<Z>(
  key: InjectionKey<Z> | string,
  defaultValue?: Z
): readonly [
  () => Z,
  (context: Z, app?: App) => Z
]

// Dynamic key mode
function createContext<Z>(
  options?: CreateContextOptions
): readonly [
  (key: string, defaultValue?: Z) => Z,
  (key: string, context: Z, app?: App) => Z
]

Parameters

key
InjectionKey<Z> | string
Static injection key. When provided, the key is fixed at creation time.
options
CreateContextOptions
Configuration object for dynamic key mode.
options.suffix
string
Optional suffix to append to the runtime key (e.g., 'v0:panel' + ':item''v0:panel:item')
defaultValue
Z
Default value to return when context is not found. Only valid in static key mode.

Return Value

[useContext, provideContext]
readonly tuple
A readonly tuple containing two functions:
useContext
() => Z | (key: string, defaultValue?: Z) => Z
Retrieves the context. In static mode, takes no arguments. In dynamic mode, requires a key string.Throws an error if context is not found and no default value is provided.
provideContext
(context: Z, app?: App) => Z | (key: string, context: Z, app?: App) => Z
Provides the context to descendant components. In static mode, takes context and optional app. In dynamic mode, also requires a key string.When app is provided, context is made available at application level. Otherwise, provided at component level.Returns the provided context value.

Usage

import { createContext } from '#v0/composables'

interface ThemeContext {
  primary: string
  secondary: string
}

// Create context with fixed key
const [useTheme, provideTheme] = createContext<ThemeContext>('v0:theme')

// In parent component
const theme: ThemeContext = {
  primary: '#1976d2',
  secondary: '#424242'
}
provideTheme(theme)

// In child component
const theme = useTheme() // Injects from 'v0:theme'
console.log(theme.primary) // '#1976d2'

Standalone Functions

You can also use the low-level functions directly:
import { useContext } from '#v0/composables'

// Inject with string key
const context = useContext<MyContext>('my-context')

// Inject with symbol key
const key: InjectionKey<MyContext> = Symbol('my-context')
const context = useContext<MyContext>(key)

// With default value
const context = useContext<MyContext>('my-context', defaultContext)

Error Handling

Unlike Vue’s native inject, useContext throws descriptive errors when context is missing:
const [useTheme] = createContext<ThemeContext>('v0:theme')

// If parent didn't provide context:
const theme = useTheme()
// ❌ Error: Context "v0:theme" not found. Ensure it's provided by an ancestor.
This prevents silent failures and makes debugging easier.

Type Safety

interface UserContext {
  id: number
  name: string
}

const [useUser, provideUser] = createContext<UserContext>('v0:user')

// ✅ Type-safe provision
provideUser({ id: 1, name: 'Alice' })

// ❌ TypeScript error: missing required properties
provideUser({ id: 1 })

// ✅ Type-safe consumption
const user = useUser()
console.log(user.name.toUpperCase()) // TypeScript knows 'name' exists

Best Practices

Export InjectionKey symbols to prevent key collisions:
export const ThemeKey: InjectionKey<ThemeContext> = Symbol('v0:theme')
export const [useTheme, provideTheme] = createContext<ThemeContext>(ThemeKey)
  • Static key mode: Use for single, well-known contexts (theme, router, i18n)
  • Dynamic key mode: Use when multiple instances need different keys (nested panels, list items)
  • Suffix mode: Use when you need scoped variants of the same context type
Only provide default values when it’s safe for components to work without explicit provision. For required contexts, let the error throw to catch configuration mistakes early.

createTrinity

Combine context with default instances

createPlugin

Create Vue plugins with context provision

Build docs developers (and LLMs) love