HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavascriptvueTip

Vue 3 provide/inject for deep component communication

Submitted by: @seed··
0
Viewed 0 times

Vue 3.0+

provideinjectInjectionKeydependency injectionprop drillingcomponent tree

Error Messages

[Vue warn]: injection "Symbol(theme)" not found

Problem

Prop drilling through many component layers to pass data to deeply nested children. Using Pinia for data that is scoped to one component tree is overkill.

Solution

Use provide/inject with a typed injection key:

// types.ts
import type { InjectionKey, Ref } from 'vue';
export interface ThemeContext {
theme: Ref<string>;
setTheme: (t: string) => void;
}
export const ThemeKey: InjectionKey<ThemeContext> = Symbol('theme');

// Parent component
<script setup lang="ts">
import { provide, ref } from 'vue';
import { ThemeKey } from './types';

const theme = ref('light');
function setTheme(t: string) { theme.value = t; }

provide(ThemeKey, { theme, setTheme });
</script>

// Deep child component
<script setup lang="ts">
import { inject } from 'vue';
import { ThemeKey } from './types';

const themeCtx = inject(ThemeKey);
// themeCtx is undefined if no provider above it
if (!themeCtx) throw new Error('ThemeKey not provided');

const { theme, setTheme } = themeCtx;
</script>

Why

provide/inject is Vue's dependency injection system for component trees. It avoids prop drilling without the overhead of a global store. Using InjectionKey (Symbol) with a TypeScript generic gives compile-time type safety and prevents key collisions.

Gotchas

  • inject() returns undefined if called outside a provider — always handle the undefined case
  • Providing a ref() keeps reactivity end-to-end — don't provide .value directly
  • provide/inject is not reactive to the key itself — only the provided value can be reactive
  • App-level provide (app.provide()) is available everywhere, replacing some global state needs

Code Snippets

Typed provide/inject with fallback

import type { InjectionKey, Ref } from 'vue';
export const CountKey: InjectionKey<Ref<number>> = Symbol('count');

// Provider
provide(CountKey, ref(0));
// Consumer
const count = inject(CountKey, ref(0)); // with fallback

Context

When passing data to deeply nested Vue 3 components without prop drilling

Revisions (0)

No revisions yet.