diff --git a/packages/server-renderer/__tests__/render.spec.ts b/packages/server-renderer/__tests__/render.spec.ts index d0a5223b2ff..e0136cb5c97 100644 --- a/packages/server-renderer/__tests__/render.spec.ts +++ b/packages/server-renderer/__tests__/render.spec.ts @@ -1229,5 +1229,23 @@ function testRender(type: string, render: typeof renderToString) { // during the render phase expect(getterSpy).toHaveBeenCalledTimes(2) }) + + test('props modifiers in render attrs', async () => { + const app = createApp({ + setup() { + return () => + h( + 'div', + { + '^attr': 'attr', + '.prop': 'prop', + }, + 'Functional Component', + ) + }, + }) + const html = await render(app) + expect(html).toBe(`
Functional Component
`) + }) }) } diff --git a/packages/server-renderer/src/helpers/ssrRenderAttrs.ts b/packages/server-renderer/src/helpers/ssrRenderAttrs.ts index b082da03fe8..b031079e92e 100644 --- a/packages/server-renderer/src/helpers/ssrRenderAttrs.ts +++ b/packages/server-renderer/src/helpers/ssrRenderAttrs.ts @@ -29,15 +29,19 @@ export function ssrRenderAttrs( tag?: string, ): string { let ret = '' - for (const key in props) { + for (let key in props) { if ( shouldIgnoreProp(key) || isOn(key) || - (tag === 'textarea' && key === 'value') + (tag === 'textarea' && key === 'value') || + // force as property (not rendered in SSR) + key.startsWith('.') ) { continue } const value = props[key] + // force as attribute + if (key.startsWith('^')) key = key.slice(1) if (key === 'class') { ret += ` class="${ssrRenderClass(value)}"` } else if (key === 'style') {