SyntaxStudy
Sign Up
Vue.js Provide / Inject for Deep Prop Passing
Vue.js Beginner 1 min read

Provide / Inject for Deep Prop Passing

When data needs to travel several component levels down — a pattern often called "prop drilling" — `provide` and `inject` offer a cleaner alternative. A parent component calls `provide(key, value)` to make a value available to all of its descendants, no matter how deeply nested. Any descendant can then call `inject(key)` to receive that value without the intermediate components needing to know it exists. To keep the data reactive you should provide a `ref` or `reactive` object rather than a plain value. Descendants that inject a `ref` receive the same reactive reference and will re-render when it changes. To prevent descendants from accidentally mutating provided state, wrap it in `readonly()` before providing it and expose a dedicated mutator function alongside it. Vue's built-in dependency injection is component-scoped — it does not replace a proper state management solution like Pinia for truly global state. It is most appropriate for shared configuration within a sub-tree: a theme token, the current form context, or a parent list's selection state shared with its item children.
Example
<!-- ThemeProvider.vue — provides theme to all descendants -->
<script setup>
import { ref, provide, readonly } from 'vue';

const theme    = ref('light');
const setTheme = (t) => { theme.value = t; };

// Provide readonly ref + mutator
provide('theme',    readonly(theme));
provide('setTheme', setTheme);
</script>
<template><slot /></template>

<!-- ─────────────────────────────────────── -->

<!-- DeepChild.vue — injects without prop drilling -->
<template>
  <div :class="'app-theme--' + theme">
    <p>Current theme: {{ theme }}</p>
    <button @click="setTheme('dark')">Dark</button>
    <button @click="setTheme('light')">Light</button>
  </div>
</template>

<script setup>
import { inject } from 'vue';

const theme    = inject('theme',    'light'); // fallback 'light'
const setTheme = inject('setTheme', () => {});
</script>