Meituan-Dianping/mpvue · warning
<transition> can only be used on a single element. Use <tran
Error message
<transition> can only be used on a single element. Use <transition-group> for lists.
What it means
<transition> animates exactly one element at a time by toggling classes on `children[0]`. When its slot renders more than one child, Vue cannot decide which element to animate, so in development it warns that transition can only be used on a single element and suggests <transition-group> for lists. The render still proceeds using the first child, but additional children are not animated and behavior is undefined.
Source
Thrown at src/platforms/web/runtime/components/transition.js:99
props: transitionProps,
abstract: true,
render (h: Function) {
let children: ?Array<VNode> = this.$options._renderChildren
if (!children) {
return
}
// filter out text nodes (possible whitespaces)
children = children.filter((c: VNode) => c.tag || isAsyncPlaceholder(c))
/* istanbul ignore if */
if (!children.length) {
return
}
// warn multiple elements
if (process.env.NODE_ENV !== 'production' && children.length > 1) {
warn(
'<transition> can only be used on a single element. Use ' +
'<transition-group> for lists.',
this.$parent
)
}
const mode: string = this.mode
// warn invalid mode
if (process.env.NODE_ENV !== 'production' &&
mode && mode !== 'in-out' && mode !== 'out-in'
) {
warn(
'invalid <transition> mode: ' + mode,
this.$parent
)
}
View on GitHub (pinned to 6c5d78ee04)
Solutions
- Ensure the transition contains exactly one element: use v-if/v-else so only one renders at a time.
- If multiple items should animate independently, switch to <transition-group> with keyed children.
- Move any extra sibling elements outside the <transition> wrapper.
- Wrap multiple always-present elements into one container element inside the transition.
Example fix
// before
<transition name="fade">
<div v-if="ok">A</div>
<div v-else>B</div>
<span>note</span>
</transition>
// after
<div>
<transition name="fade">
<div v-if="ok">A</div>
<div v-else>B</div>
</transition>
<span>note</span>
</div> Defensive patterns
Strategy: validation
Validate before calling
// check slot renders a single element before enabling transition
const childCount = document.querySelectorAll('#transition-wrapper > *').length
if (childCount > 1) console.warn('<transition> slot renders ' + childCount + ' elements; must be exactly 1') Type guard
const hasSingleChild = children => Array.isArray(children) && children.length === 1
Prevention
- Use v-if/v-else pairs so only one element exists at a time inside <transition>.
- Keep auxiliary siblings outside the transition wrapper.
- Use <transition-group> whenever more than one element may render.
- Review templates after refactoring v-show into v-if branches.
When it happens
Trigger: Placing two or more sibling elements directly inside <transition>, e.g. `<transition><div v-if="a"/><div v-else/><div>extra</div></transition>`; v-for inside <transition>; a v-if/v-else-if/v-else chain with an extra unconditioned sibling.
Common situations: Adding a wrapper element or icon next to the toggled element inside transition; forgetting that comments/whitespace text nodes are filtered but extra elements are not; converting a v-show toggle into two v-if elements.
Related errors
- invalid <transition> mode: ${mode}
- `key` does not work on <slot> because slots are abstract out
- Invalid Component definition: ${String(Ctor)}
- <transition-group> children must be keyed: <${name}>
- <transition> explicit ${name} duration is not a valid number
AI-assisted analysis of Meituan-Dianping/mpvue@6c5d78ee04 (2026-09-02).
Data as JSON: /api/errors/afa8b20081aee22f.
Report an issue: GitHub.