fix(jsx): normalize SVG attributes on the <svg> root element (#4893)
* fix(jsx): normalize SVG attributes on the <svg> root element `<svg strokeWidth="1.5">` was output as-is by SSR, but the DOM renderer converted it to `stroke-width`. This broke icon libraries that set stroke/fill attributes on the <svg> root, and it caused SSR and DOM to produce different HTML for the same JSX. Background: - Icon libraries put these attributes on the <svg> root so the child paths can inherit them. Example from Heroicons: https://github.com/tailwindlabs/heroicons/blob/master/optimized/24/outline/pencil-square.svg - React also converts `strokeWidth` -> `stroke-width` on the root (checked with `react-dom/server@18.3.1` `renderToStaticMarkup`). - The HTML spec says that when the parser sees a `<svg>` start tag, it inserts "a foreign element for the token, with SVG namespace". So the <svg> element itself is in the SVG namespace, not only its children: https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody:adjust-svg-attributes Root cause: the factory put only the children of `<svg>` inside the namespace provider (`svg > Provider > children`). When SSR rendered the <svg>'s own attributes, `useContext(nameSpaceContext)` returned the default `""` instead of `"svg"`, so `toSVGAttributeName` was skipped. Fix: put the <svg> element itself inside the provider too (`Provider > svg > children`), so the <svg>'s own attributes also run with the `"svg"` context. The `<head>` branch of the factory is left unchanged. Its context value `"head"` is a Hono-internal flag used to stop <title> / <meta> / <script> from hoisting to document metadata when they are already inside <head>. It is not a spec namespace and is never read when rendering <head>'s own attributes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(jsx): keep <svg> node shape and normalize at render time Preserve the JSXNode shape for `<svg>` (tag/type/ref/cloneElement compatibility) and switch SVG attribute normalization to also kick in when the rendered tag itself is `svg`, instead of wrapping the node in a namespace Provider. Co-authored-by: Taku Amano <taku@taaas.jp>
K
kobaken committed
bfba97ca7ea3d4541a3419f1749e5a1a3e8f1727
Parent: 90d4182
Committed by GitHub <noreply@github.com>
on 5/1/2026, 9:01:56 AM