Vue Provide/Inject
Share data across component hierarchy
🔗 What is Provide/Inject?
Provide and Inject enable parent components to share data with all descendants without prop drilling. The parent provides values, and any descendant can inject them, regardless of component depth in the hierarchy.
<!-- Parent Component -->
<script setup>
import { provide, ref } from 'vue'
const theme = ref('dark')
provide('theme', theme)
</script>
<!-- Child Component (any level deep) -->
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
// Now can use theme.value
</script>
Key Provide/Inject Concepts
Provide
Share data from parent
provide('key', value)
Inject
Receive data in descendants
const value = inject('key')
Reactivity
Provided refs stay reactive
const count = ref(0)
provide('count', count)
Default Values
Fallback if not provided
inject('key', 'default')
🔹 Basic Provide/Inject
Share data from parent to any descendant:
<!-- App.vue (Parent) -->
<template>
<div>
<h1>App</h1>
<ChildComponent />
</div>
</template>
<script setup>
import { provide, ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const username = ref('John Doe')
const userRole = ref('admin')
// Provide values to all descendants
provide('username', username)
provide('userRole', userRole)
</script>
<!-- GrandchildComponent.vue (Deep descendant) -->
<template>
<div>
<p>User: {{ username }}</p>
<p>Role: {{ userRole }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue'
// Inject values from ancestor
const username = inject('username')
const userRole = inject('userRole')
</script>
🔹 Reactive Provide/Inject
Provided reactive values update across all components:
<!-- Parent Component -->
<template>
<div>
<button @click="count++">Increment: {{ count }}</button>
<ChildComponent />
</div>
</template>
<script setup>
import { provide, ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const count = ref(0)
// Provide reactive ref
provide('count', count)
</script>
<!-- Child Component -->
<template>
<div>
<p>Count in child: {{ count }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue'
// Inject reactive value
const count = inject('count')
// count.value updates automatically!
</script>
🔹 Provide Functions
Share methods to modify provided data:
<!-- Parent Component -->
<template>
<div>
<h2>Theme: {{ theme }}</h2>
<ChildComponent />
</div>
</template>
<script setup>
import { provide, ref } from 'vue'
import ChildComponent from './ChildComponent.vue'
const theme = ref('light')
function toggleTheme() {
theme.value = theme.value === 'light' ? 'dark' : 'light'
}
// Provide both data and function
provide('theme', theme)
provide('toggleTheme', toggleTheme)
</script>
<!-- Child Component -->
<template>
<div>
<p>Current theme: {{ theme }}</p>
<button @click="toggleTheme">Toggle Theme</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
const theme = inject('theme')
const toggleTheme = inject('toggleTheme')
</script>
🔹 Default Values
Provide fallback values when injection might fail:
<template>
<div>
<p>User: {{ username }}</p>
<p>Theme: {{ theme }}</p>
<p>Language: {{ language }}</p>
</div>
</template>
<script setup>
import { inject } from 'vue'
// Inject with default values
const username = inject('username', 'Guest')
const theme = inject('theme', 'light')
const language = inject('language', 'en')
// If parent doesn't provide these values,
// defaults will be used
</script>
🔹 Provide Object Pattern
Group related data and methods together:
<!-- Parent Component -->
<script setup>
import { provide, ref, readonly } from 'vue'
const user = ref({
name: 'Alice',
email: '[email protected]',
role: 'admin'
})
function updateUser(updates) {
user.value = { ...user.value, ...updates }
}
// Provide as object
provide('userStore', {
user: readonly(user), // Make read-only
updateUser
})
</script>
<!-- Child Component -->
<template>
<div>
<p>{{ userStore.user.name }}</p>
<button @click="changeName">Change Name</button>
</div>
</template>
<script setup>
import { inject } from 'vue'
const userStore = inject('userStore')
function changeName() {
userStore.updateUser({ name: 'Bob' })
}
</script>
🔹 App-Level Provide
Provide values to entire application:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
const app = createApp(App)
// Provide at app level
app.provide('apiUrl', 'https://api.example.com')
app.provide('appVersion', '1.0.0')
app.mount('#app')
// Now any component can inject these values
// const apiUrl = inject('apiUrl')
// const appVersion = inject('appVersion')