Consider a Vue compound component where Modal provides context and ModalHeader and ModalBody consume it. What will be the visible output?
<template>
<Modal>
<ModalHeader>Welcome</ModalHeader>
<ModalBody>This is the body content.</ModalBody>
</Modal>
</template>
<script setup>
import { provide, inject, ref } from 'vue'
const Modal = {
setup(_, { slots }) {
const title = ref('Default Title')
provide('modalTitle', title)
return () => (
<section aria-modal="true" role="dialog">
{slots.default()}
</section>
)
}
}
const ModalHeader = {
setup(_, { slots }) {
const title = inject('modalTitle')
return () => (
<header><h1>{slots.default ? slots.default() : title.value}</h1></header>
)
}
}
const ModalBody = {
setup(_, { slots }) {
return () => <main>{slots.default()}</main>
}
}
</script>Look at how ModalHeader uses the slot content versus the injected title.
The ModalHeader component renders its slot content if provided. Since 'Welcome' is passed as slot content, it shows that instead of the default injected title.
In this compound component pattern, a shared state is provided by the parent and updated by a child button. What will be the final value of count after clicking the button once?
<template>
<Counter>
<CounterDisplay />
<CounterButton />
</Counter>
</template>
<script setup>
import { ref, provide, inject } from 'vue'
const Counter = {
setup(_, { slots }) {
const count = ref(0)
provide('count', count)
provide('increment', () => { count.value++ })
return () => slots.default()
}
}
const CounterDisplay = {
setup() {
const count = inject('count')
return () => <p>Count: {count.value}</p>
}
}
const CounterButton = {
setup() {
const increment = inject('increment')
return () => <button onClick={increment}>Add</button>
}
}
</script>Think about how the increment function changes the shared count state.
Clicking the button calls increment, which increases count.value by 1. So the displayed count updates from 0 to 1.
Which code snippet correctly implements a compound component pattern in Vue 3 using provide and inject with slots?
Remember that slots.default is a function and inject returns a ref if provided a ref.
Option A correctly calls slots.default() to render slot content and accesses data.value from the injected ref. Other options either misuse slots or access ref incorrectly.
Given this compound component, why does clicking the button not update the displayed count?
<template>
<Counter>
<CounterDisplay />
<CounterButton />
</Counter>
</template>
<script setup>
import { ref, provide, inject } from 'vue'
const Counter = {
setup(_, { slots }) {
const count = ref(0)
provide('count', count)
provide('increment', () => { count.value++ })
return () => slots.default()
}
}
const CounterDisplay = {
setup() {
const count = inject('count')
return () => <p>Count: {count.value}</p>
}
}
const CounterButton = {
setup() {
const increment = inject('increment')
return () => <button onClick={increment}>Add</button>
}
}
</script>Check how the reactive ref is accessed in the display component.
The CounterDisplay component renders {count} which is the ref object, not its value. It should render {count.value} to show the number.
Why would a developer choose to use the compound components pattern instead of passing props directly to child components?
Think about how state and functions are shared between parent and children without passing props down many levels.
The compound components pattern uses provide/inject to share state and behavior implicitly, avoiding prop drilling and allowing flexible component composition.