Repository navigation
fix(react): render Stencil props as attributes during SSR - #850
Open
Burzmalian wants to merge 7 commits into
Open
Burzmalian wants to merge 7 commits into
Burzmalian wants to merge 7 commits into
Conversation
Burzmalian
force-pushed
the
fix/react-ssr-attributes
branch
2 times, most recently
from
September 28, 2026 21:27
585130a to
7b27800
Compare
Burzmalian
force-pushed
the
fix/react-ssr-attributes
branch
from
September 29, 2026 14:46
9178a8a to
c491ee6
Compare
davidpett
enabled auto-merge (rebase)
September 30, 2026 00:05
auto-merge was automatically disabled
October 7, 2026 18:28
Pull request was closed
Burzmalian
force-pushed
the
fix/react-ssr-attributes
branch
2 times, most recently
from
October 13, 2026 18:33
5626c05 to
1262689
Compare
The client wrapper set every Stencil prop as a JS property after mount, so server HTML had bare tags and elements upgraded with default props until React hydrated. On the server, render the tag with the props as attributes, mapped through the element class (prototype accessors and observedAttributes). Non-primitive props stay client-only and false is omitted, matching the SSR wrapper. suppressHydrationWarning keeps React from reporting the extra attributes. Fixes stenciljs#848
… map Generate the same prop-to-attribute map the server wrappers use into the client wrappers and prefer it on the server, so @prop({ attribute }) names are honoured. The observedAttributes lookup stays as a fallback for hand-written wrappers. Document that this covers host attributes only.
`key in prototype` walks the whole chain, so under a server DOM shim inherited props like id or title would be mistaken for Stencil props and dropped. Check own accessors on the component prototype chain only, stopping at HTMLElement.
…its like Stencil - Client wrapper mirrors the server's attribute set in a layout effect, so a prop set back to false or undefined removes its attribute; @lit/react only sets properties and Stencil does not reflect them - Attribute fallback splits on digits (line1 -> line-1), matching Stencil's toDashCase - Prop detection and attribute naming shared between the server and client paths - jsdom spec: server HTML hydrates without warnings and attributes follow prop changes - Keep suppressHydrationWarning on the client render: @lit/react's node build does not set it
The client layout effect updated or added an attribute for every Stencil prop, so elements React created on the client gained host attributes they never had. Limit it to attributes already present: server-rendered hosts stay in sync with their props, client-rendered hosts stay property-only as before.
stenciljs#847 rewrote the generator with string templates; the client wrapper keeps its properties map, placed after elementClass as before.
Burzmalian
force-pushed
the
fix/react-ssr-attributes
branch
from
October 22, 2026 17:18
1262689 to
b4271d9
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull request checklist
npm run build) was run locally for affected output targetsnpm test) were run locally and passednpm run prettier) was run locally and passedPull request type
What is the current behavior?
The client wrapper hands every Stencil prop to
@lit/react, which sets it as a JS property after mount. Server HTML therefore has bare tags. For<MyButton variant="tertiary" size="lg">Open</MyButton>the server sends:The element upgrades with its default props and only gets the real ones when React hydrates, so every page flashes the wrong state first.
Issue URL: #848
What is the new behavior?
createComponentrenders the tag directly with the Stencil props as attributes:propertiesmap the server wrappers use, now also generated into the client wrappers, so@Prop({ attribute })is honoured. Own accessors on the component prototype chain (aboveHTMLElement) tell Stencil props from pass-through props such asidorslot. Hand-written wrappers without the map fall back to the kebab-case name checked againststatic observedAttributes.falseis omitted, same as the SSR wrapper inssr.tsx.suppressHydrationWarningis set on the element in both the server and the client render, so React does not report the server-only attributes.hydrateModuleor@stencil/ssr.Does this introduce a breaking change?
Server HTML gains attributes. Hydration was checked in Chrome with React 19.2: no warnings, attributes kept.
Other information
Tested in a Next.js 16 app with 107 components: no flash, no hydration errors, TTFB unchanged. Tests cover attribute mapping, omitted values, pass-through props and a class without
observedAttributes.