provide/inject let an ancestor component supply data to any descendant, no matter how deep, without passing props through every intermediate component. They solve prop drilling.
The problem: prop drilling
App → Layout → Sidebar → Menu → MenuItem
provide/inject let an ancestor component supply data to any descendant, no matter how deep, without passing props through every intermediate component. They solve prop drilling.
App → Layout → Sidebar → Menu → MenuItem
If only MenuItem needs the theme, passing it as a prop through Layout, Sidebar, and Menu (which don't use it) is tedious and noisy. provide/inject skip the middle.
<!-- App.vue -->
<script setup>
import { provide, ref } from "vue";
const theme = ref("dark");
provide("theme", theme); // make `theme` available to ALL descendants
provide("toggleTheme", () => { // can provide functions too
theme.value = theme.value === "dark" ? "light" : "dark";
});
</script>
<!-- MenuItem.vue (deeply nested) -->
<script setup>
import { inject } from "vue";
const theme = inject("theme"); // get it directly — no props in between
const toggleTheme = inject("toggleTheme");
const color = inject("color", "blue"); // with a default fallback
</script>
// ✅ provide a ref/reactive so descendants see updates
provide("theme", theme); // theme is a ref → reactive
// ❌ provide("theme", theme.value) → passes a snapshot, not reactive
Provide the reactive object (the ref, not its .value) so when it changes, all injecting components update.
import { themeKey } from "./keys"; // export const themeKey = Symbol()
provide(themeKey, theme); // avoids string-key collisions
provide/inject → pass data down a specific subtree (theme, form context, a service)
Pinia → global, app-wide shared state (user, cart) usable anywhere
Use provide/inject for dependency-injection within a subtree; reach for Pinia when state is truly global or shared across unrelated parts of the app.
provide/inject eliminate prop drilling for data that many nested components share (themes, locale, form/context, plugin services).
Knowing to provide reactive values (so updates propagate), use defaults/Symbol keys, and distinguish it from global state (Pinia) lets you pass shared context cleanly through deep component trees.
A library of IT interview questions with detailed answers — from Junior to Senior.
Donate