diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts
index 20519cf997f..4a9e0fac2b6 100644
--- a/packages/runtime-core/__tests__/hydration.spec.ts
+++ b/packages/runtime-core/__tests__/hydration.spec.ts
@@ -1654,6 +1654,29 @@ describe('SSR hydration', () => {
expect(`mismatch`).not.toHaveBeenWarned()
})
+ test('transition appear work with pre-existing class', () => {
+ const { vnode, container } = mountWithHydration(
+ `foo
`,
+ () =>
+ h(
+ Transition,
+ { appear: true },
+ {
+ default: () => h('div', { class: 'foo' }, 'foo'),
+ },
+ ),
+ )
+ expect(container.firstChild).toMatchInlineSnapshot(`
+
+ foo
+
+ `)
+ expect(vnode.el).toBe(container.firstChild)
+ expect(`mismatch`).not.toHaveBeenWarned()
+ })
+
test('transition appear with v-if', () => {
const show = false
const { vnode, container } = mountWithHydration(
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index a94ff356810..49fb6e594cf 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -398,9 +398,10 @@ export function createHydrationFunctions(
parentComponent.vnode.props.appear
const content = (el as HTMLTemplateElement).content
- .firstChild as Element
+ .firstChild as Element & { $cls: string | null }
if (needCallTransitionHooks) {
+ content.$cls = content.getAttribute('class')
transition!.beforeEnter(content)
}
@@ -786,7 +787,7 @@ export function createHydrationFunctions(
* Dev only
*/
function propHasMismatch(
- el: Element,
+ el: Element & { $cls?: string | null },
key: string,
clientValue: any,
vnode: VNode,
@@ -799,7 +800,12 @@ function propHasMismatch(
if (key === 'class') {
// classes might be in different order, but that doesn't affect cascade
// so we just need to check if the class lists contain the same classes.
- actual = el.getAttribute('class')
+ if (el.$cls) {
+ actual = el.$cls
+ delete el.$cls
+ } else {
+ actual = el.getAttribute('class')
+ }
expected = normalizeClass(clientValue)
if (!isSetEqual(toClassSet(actual || ''), toClassSet(expected))) {
mismatchType = MismatchTypes.CLASS