diff --git a/packages/runtime-core/__tests__/hydration.spec.ts b/packages/runtime-core/__tests__/hydration.spec.ts
index d3cfd47c6be..dce0cd4e13e 100644
--- a/packages/runtime-core/__tests__/hydration.spec.ts
+++ b/packages/runtime-core/__tests__/hydration.spec.ts
@@ -939,6 +939,30 @@ describe('SSR hydration', () => {
expect((container.firstChild!.firstChild as any)._value).toBe(true)
})
+ test('force hydrate prop with `.prop` modifier', () => {
+ const { container } = mountWithHydration(
+ '',
+ () =>
+ h('input', {
+ type: 'checkbox',
+ '.indeterminate': true
+ })
+ )
+ expect((container.firstChild! as any).indeterminate).toBe(true)
+ })
+
+ test('force hydrate prop with `.attr` modifier', () => {
+ const { container } = mountWithHydration(
+ '',
+ () =>
+ h('input', {
+ type: 'checkbox',
+ '^x': 1
+ })
+ )
+ expect((container.firstChild! as any).getAttribute('x')).toBe('1')
+ })
+
// #5728
test('empty text node in slot', () => {
const Comp = {
diff --git a/packages/runtime-core/src/hydration.ts b/packages/runtime-core/src/hydration.ts
index 89a00886332..f29e7d25813 100644
--- a/packages/runtime-core/src/hydration.ts
+++ b/packages/runtime-core/src/hydration.ts
@@ -329,7 +329,10 @@ export function createHydrationFunctions(
for (const key in props) {
if (
(forcePatchValue && key.endsWith('value')) ||
- (isOn(key) && !isReservedProp(key))
+ (isOn(key) && !isReservedProp(key)) ||
+ // support .prop & .attr modifiers
+ key[0] === '.' ||
+ key[0] === '^'
) {
patchProp(
el,