The React Context API provides a way to (e.g., user settings, UI theme) (aka prop drilling). Although Vue.js does not provide the same abstraction out of the box, in this article, we’ll see that share properties that are required by many components without having to pass a prop through every level of the tree in Vue 3, we have all the tools we need to replicate the same functionality quickly. User settings provider In this example, we look at how we can use this pattern to everywhere in our entire application. make certain information globally available The component you see beneath, provides a reactive with some default values and an function for setting properties on the object. ProvideUserSettings state update() state { provide, reactive, readonly, toRefs, } ; UserSettingsStateSymbol = ( ); UserSettingsUpdateSymbol = ( ); { setup() { state = reactive({ : , : , }); provide(UserSettingsStateSymbol, toRefs(readonly(state))); update = { state[property] = value; }; provide(UserSettingsUpdateSymbol, update); }, render() { .$slots.default(); }, }; // src/components/ProvideUserSettings.js import from 'vue' // We use symbols as a unique identifiers. export const Symbol 'User settings provider state identifier' export const Symbol 'User settings update provider identifier' export default const language 'en' theme 'light' // Using `toRefs()` makes it possible to use // spreading in the consuming component. // Making the return value `readonly()` prevents // users from mutating global state. const ( ) => property, value // Our provider component is a renderless component // it does not render any markup of its own. return this Next we take a look at how we can use the component in our application. ProvideUserSettings <!-- src/App.vue --> < > script ProvideUserSettings ; { : , : { ProvideUserSettings, }, }; import from './components/ProvideUserSettings' export default name 'App' components </ > script < > template < > ProvideUserSettings < > div <!-- ... --> </ > div </ > ProvideUserSettings </ > template We probably need the settings in a lot of different components throughout our application. Because of that, it makes sense to put the provider at the root level inside of our component. App So we now have access to the user settings from anywhere in our component tree. <!-- src/components/ButtonPrimary.vue --> < > script { inject } ; { UserSettingsStateSymbol } ; { setup() { { theme } = inject(UserSettingsStateSymbol); { theme }; }, }; import from 'vue' import from './ProvideUserSettings' export default const return </ > script < > template < = > ButtonBase :class "$style[`t-${theme}`]" < /> slot </ > ButtonBase </ > template < > style module { } { } .t-light /* ... */ .t-dark /* ... */ </ > style Above, In the following example, we explore how to the state from any component in our application. we see how to consume the state of the injected context. update Enable darkmode Enable lightmode <!-- src/components/ThemeSwitcher.vue --> < > script { inject } ; { UserSettingsUpdateSymbol } ; { setup() { updateUserSettings = inject(UserSettingsUpdateSymbol); updateTheme = updateUserSettings( , value); { updateTheme }; }, }; import from 'vue' import from './ProvideUserSettings' export default const const => value 'theme' return </ > script < > template < > div < @ = > button click "updateTheme('dark')" </ > button < @ = > button click "updateTheme('light')" </ > button </ > div </ > template This time we inject the function with the . update() UserSettingsUpdateSymbol We wrap the injected function in a new function which directly sets the property of our user settings object. updateTheme() theme In theory, we could not wrap our state with and mutate it directly. But this can create a maintenance nightmare because it becomes tough to determine where we make changes to the (global) state. readonly() When we click one of the two buttons, the user settings state is updated, and because it is a reactive object, all components which are using the injected user settings state are updated too. Wrapping it up Although Vue.js does not have the concept of Context built-in like React, as we’ve seen in this article, it is straightforward to implement something similar to that with Vue 3 ourselves. provide/inject Previously published at https://markus.oberlehner.net/blog/context-and-provider-pattern-with-the-vue-3-composition-api/