Tutorials Logic, IN +91 8092939553 info@tutorialslogic.com
FAQs Support
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Interview Questions Website Development
Compiler Tutorials

Provide / Inject

What is Provide / Inject?

provide and inject solve the prop drilling problem — passing data through many layers of components that don't need it. A parent component provides data, and any descendant (no matter how deep) can inject it directly.

Unlike props, provide/inject skips intermediate components entirely. It's Vue's built-in dependency injection system.

FeaturePropsProvide/InjectPinia
ScopeParent → direct childAncestor → any descendantGlobal
ReactivityYesYes (with ref/reactive)Yes
Best forDirect parent-childPlugin-like data, theme, localeApp-wide state
Provide / Inject — Theme, Locale, App Config
<!-- App.vue — provides data to all descendants -->
<template>
  <div :data-theme="theme">
    <Navbar />
    <Main />
    <Footer />
  </div>
</template>

<script setup>
import { ref, provide, readonly } from 'vue'

// Provide reactive data
const theme = ref('light')
const locale = ref('en')
const user = ref({ name: 'Alice', role: 'admin' })

// Provide a function to update theme (keeps mutation in provider)
function toggleTheme() {
  theme.value = theme.value === 'light' ? 'dark' : 'light'
}

// provide(key, value)
provide('theme', readonly(theme))       // read-only to prevent mutation
provide('toggleTheme', toggleTheme)     // function to update
provide('locale', locale)
provide('currentUser', readonly(user))

// Provide an object with multiple values
provide('appConfig', {
  apiUrl: 'https://api.example.com',
  version: '2.0.0',
  features: { darkMode: true, notifications: true }
})
</script>
<!-- DeepChild.vue — can be nested 10 levels deep, still works -->
<template>
  <div :class="`theme-${theme}`">
    <p>Theme: {{ theme }}</p>
    <p>User: {{ currentUser?.name }}</p>
    <p>API: {{ appConfig?.apiUrl }}</p>
    <button @click="toggleTheme">Toggle Theme</button>
  </div>
</template>

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

// inject(key, defaultValue)
const theme       = inject('theme', 'light')        // with default
const toggleTheme = inject('toggleTheme', () => {}) // with default
const currentUser = inject('currentUser')
const appConfig   = inject('appConfig')

// inject returns undefined if not provided (no error)
const locale = inject('locale')
</script>

<!-- Symbol keys — avoid naming collisions in large apps -->
<!-- keys.js -->
<!-- export const THEME_KEY = Symbol('theme') -->
<!-- export const USER_KEY  = Symbol('user') -->

<!-- Provider: provide(THEME_KEY, theme) -->
<!-- Consumer: const theme = inject(THEME_KEY) -->
// composables/useTheme.js — wrap provide/inject in composables
import { ref, provide, inject, readonly } from 'vue'

const THEME_KEY = Symbol('theme')

// Used in the provider component (App.vue or layout)
export function provideTheme() {
    const theme = ref('light')

    function toggleTheme() {
        theme.value = theme.value === 'light' ? 'dark' : 'light'
    }

    function setTheme(newTheme) {
        theme.value = newTheme
    }

    provide(THEME_KEY, {
        theme: readonly(theme),
        toggleTheme,
        setTheme,
    })

    return { theme, toggleTheme, setTheme }
}

// Used in any descendant component
export function useTheme() {
    const context = inject(THEME_KEY)
    if (!context) {
        throw new Error('useTheme() must be used within a component that calls provideTheme()')
    }
    return context
}

// Usage in App.vue:
// import { provideTheme } from '@/composables/useTheme'
// provideTheme()

// Usage in any child:
// import { useTheme } from '@/composables/useTheme'
// const { theme, toggleTheme } = useTheme()

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.