Skip to content

fix(html): set attribute for expressions on nested svg elements - #316

Merged
smalluban merged 1 commit into
hybridsjs:mainfrom
dobexx:fix/template-svg-nested-attributes
Sep 25, 2026
Merged

smalluban merged 1 commit into
hybridsjs:mainfrom
dobexx:fix/template-svg-nested-attributes

Conversation

@dobexx

@dobexx dobexx commented Sep 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #315.

Since 8.2.20, an expression in an attribute of a nested SVG element in an html template (e.g. <rect x="${x}">) throws a TypeError when the element has a read-only property of that name (x, width, points, transform, href on <use>, viewBox on <symbol>, …). Reproduction and version table in #315.

resolveProperty() only skips the <svg> root (src/template/resolvers/property.js:35, isProp = target.tagName !== "svg";). For <rect>, "x" in target is true (getter-only SVGAnimatedLength), so the assignment in property.js:48 throws in module code. The SVGElement check was introduced in 6000823 ("svg element expressions always set attribute value") and kept until 8.2.19; bdd8716 (#253) replaced it with the tag-name check while adding the camel-case fallback. The mixed-value path still checks for SVGElement (src/template/core.js:433-435), and the "svg element" tests only cover the <svg> root.

The docs suggest the svg function for the internal structure of <svg> (docs/component-model/templates.md:47). But html already parses nested SVG elements into the SVG namespace, static attributes and mixed values work, and single expressions worked up to 8.2.19, so the TypeError looks unintended.

This change restores the SVGElement check. Elements in the SVG namespace get attributes, as in svg templates and with mixed values. HTML and custom elements, also inside <foreignObject>, keep the property lookup and the camel-case fallback from bdd8716.

Side effect: a writable property without an attribute on an SVG child in an html template, such as textContent="${text}" on <text>, is set as an attribute again, as in 8.2.19 and in svg templates. Since 8.2.20 it has been set as a property. Properties that reflect an attribute, such as tabIndex, give the same result either way.

Regression test in test/spec/html.js ("svg element"): <rect x width> and <polyline points> inside <svg> in an html template. It fails without the fix (Chrome Headless: Cannot set property x of #<SVGRectElement> which has only a getter, WebKit: Attempted to assign to readonly property.) and passes with it. Full suite in Chrome Headless and WebKit: 609 of 609 with the fix, 608 of 609 without it (main alone in Chrome Headless: 608 of 608). Firefox was not run locally. Lint is clean, and prettier is clean for the changed files.

Since 8.2.20 the property resolver only skips the `<svg>` root element. An
expression like `<rect x="${x}">` inside an `html` template therefore
assigns the read-only `x` property (`SVGAnimatedLength`) and throws a
TypeError.

Check for `SVGElement` again, as up to 8.2.19 and as the mixed-value path
in core.js still does, so expressions on elements in the SVG namespace set
attributes, like in `svg` templates.
@coveralls

Copy link
Copy Markdown

Coverage Status

coverage: 99.875%. remained the same — dobexx:fix/template-svg-nested-attributes into hybridsjs:main

@smalluban smalluban left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the PR!

@smalluban
smalluban merged commit 423b571 into hybridsjs:main Sep 25, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Expressions on SVG elements nested in an html template throw since 8.2.20

3 participants