vuetifyjs/vuetify · error · Error
[Vuetify] v-expansion-panel-text needs to be placed inside v
Error message
[Vuetify] v-expansion-panel-text needs to be placed inside v-expansion-panel
What it means
VExpansionPanelText injects VExpansionPanelSymbol, provided only by <v-expansion-panel>. It throws when <v-expansion-panel-text> is rendered without a <v-expansion-panel> ancestor, because there is no panel selection/state to bind to.
Source
Thrown at packages/vuetify/src/components/VExpansionPanel/VExpansionPanelText.tsx:26
// Utilities
import { inject } from 'vue'
import { genericComponent, propsFactory, useRender } from '@/util'
export const makeVExpansionPanelTextProps = propsFactory({
...makeComponentProps(),
...makeLazyProps(),
}, 'VExpansionPanelText')
export const VExpansionPanelText = genericComponent()({
name: 'VExpansionPanelText',
props: makeVExpansionPanelTextProps(),
setup (props, { slots }) {
const expansionPanel = inject(VExpansionPanelSymbol)
if (!expansionPanel) throw new Error('[Vuetify] v-expansion-panel-text needs to be placed inside v-expansion-panel')
const { hasContent, onAfterLeave } = useLazy(props, expansionPanel.isSelected)
useRender(() => (
<VExpandTransition onAfterLeave={ onAfterLeave }>
<div
class={[
'v-expansion-panel-text',
props.class,
]}
style={ props.style }
v-show={ expansionPanel.isSelected.value }
>
{ slots.default && hasContent.value && (
<div class="v-expansion-panel-text__wrapper">
{ slots.default?.() }
</div>
)}View on GitHub (pinned to 8d153908df)
Solutions
- Nest <v-expansion-panel-text> inside <v-expansion-panel> (and that inside <v-expansion-panels>).
- Keep teleported content within the panel's provide tree.
- In tests, wrap the component in <v-expansion-panel>.
Example fix
// before
<v-expansion-panel-text>Content</v-expansion-panel-text>
// after
<v-expansion-panels>
<v-expansion-panel>
<v-expansion-panel-title>Title</v-expansion-panel-title>
<v-expansion-panel-text>Content</v-expansion-panel-text>
</v-expansion-panel>
</v-expansion-panels> Defensive patterns
Strategy: type-guard
Validate before calling
import { inject } from 'vue'
import { VExpansionPanelSymbol } from 'vuetify'
const panel = inject(VExpansionPanelSymbol, null)
if (!panel) {
// not inside a panel: render a plain div instead of v-expansion-panel-text
} Type guard
import { inject } from 'vue'
import { VExpansionPanelSymbol } from 'vuetify'
export function isInsideExpansionPanel (): boolean {
return inject(VExpansionPanelSymbol, null) != null
} Prevention
- Always nest panel text/title inside <v-expansion-panel>.
- Do not teleport panel children outside the panel tree.
- Wrap children in <v-expansion-panel> for tests.
When it happens
Trigger: Placing <v-expansion-panel-text> outside <v-expansion-panel>; rendering it via a teleport whose target is outside the panel tree; testing it in isolation.
Common situations: Copy-paste of panel text into a non-panel container; restructuring markup that drops the panel wrapper; custom builds that assemble panels dynamically and miss the wrapper.
Related errors
- [Vuetify] v-expansion-panel-title needs to be placed inside
- [Vuetify] VOtpField must be used inside VOtpInput
- [Vuetify] v-slider-thumb must be used inside v-slider or v-r
- [Vuetify] v-slider-track must be inside v-slider or v-range-
- [Vuetify] VWindowItem must be used inside VWindow
AI-assisted analysis of vuetifyjs/vuetify@8d153908df (2026-08-12).
Data as JSON: /api/errors/e0694c00c5b298b0.
Report an issue: GitHub.