How to use provide/inject in Vue

Vue provide/inject enables dependency injection across component hierarchies, allowing ancestor components to share data and services with descendant components without prop drilling. This pattern eliminates the need to pass props through multiple component levels. It’s particularly useful for global services like authentication, themes, or configuration that many components need access to.

Use provide() in ancestor components and inject() in descendant components for dependency injection.

<!-- Parent.vue - Providing data -->
<template>
  <div>
    <h1>Theme: {{ theme.current }}</h1>
    <button @click="theme.toggle">Toggle Theme</button>
    <ChildComponent />
  </div>
</template>

<script>
import { provide, reactive } from 'vue'
import ChildComponent from './ChildComponent.vue'

export default {
  components: { ChildComponent },
  setup() {
    const theme = reactive({
      current: 'light',
      toggle() {
        this.current = this.current === 'light' ? 'dark' : 'light'
      }
    })

    const user = reactive({
      name: 'John Doe',
      role: 'admin',
      isAuthenticated: true
    })

    // Provide data to descendant components
    provide('theme', theme)
    provide('user', user)

    return { theme }
  }
}
</script>
<!-- ChildComponent.vue - Injecting data -->
<template>
  <div :class="themeClass">
    <h2>Child Component</h2>
    <p>Welcome {{ user.name }}!</p>
    <p>Role: {{ user.role }}</p>
    <button @click="changeTheme">Change Theme</button>
    <GrandchildComponent />
  </div>
</template>

<script>
import { inject, computed } from 'vue'
import GrandchildComponent from './GrandchildComponent.vue'

export default {
  components: { GrandchildComponent },
  setup() {
    // Inject provided data
    const theme = inject('theme')
    const user = inject('user', { name: 'Guest', role: 'guest' }) // default value

    const themeClass = computed(() => `theme-${theme.current}`)

    const changeTheme = () => {
      theme.toggle()
    }

    return {
      theme,
      user,
      themeClass,
      changeTheme
    }
  }
}
</script>
<!-- GrandchildComponent.vue - Deep injection -->
<template>
  <div>
    <h3>Grandchild Component</h3>
    <p>Current theme: {{ theme.current }}</p>
    <p>User authenticated: {{ user.isAuthenticated ? 'Yes' : 'No' }}</p>
  </div>
</template>

<script>
import { inject } from 'vue'

export default {
  setup() {
    const theme = inject('theme')
    const user = inject('user')

    return { theme, user }
  }
}
</script>

Vue provide/inject creates a dependency injection system where provide() makes data available to all descendant components and inject() retrieves that data. The provided values are reactive and automatically update all injecting components when changed. Use string keys to identify injected values and provide default values in inject() for cases where the provider might not exist. This pattern is ideal for themes, authentication, configuration, and other cross-cutting concerns.

Best Practice Note:

This is the same provide/inject approach used in CoreUI Vue components. Use provide/inject for application-wide services, provide default values when injecting, keep injection keys consistent, maintain reactivity with reactive() or ref(), and document provided interfaces for team collaboration.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author