Skip to content

Conversation

@yurivish
Copy link
Contributor

@yurivish yurivish commented Dec 14, 2025

I confirm that I have read the contribution guidelines and will include a clear explanation of the problem, solution, and alternatives for any proposed change in behavior.

Problem Statement

There is currently no way to control the namespace of patched elements, which prevents insertion of new elements into <svg> and <math> contexts where children must be created in the appropriate XML namespace.

This PR came out of a discussion in issue #1088.

Proposed Solution

Add a new option, wrap, to datastar-patch-elements, which specifies a tag name (such as svg or math) that is used as a wrapper element when parsing the elements to be patched. The wrapper element is never inserted into the document, and is used only to influence the namespace of the elements being inserted by the patch operation.

I'm not sure about the name wrap, since the wrapping technique is an implementation detail and the wrapper element does not appear in the document. I considered calling it namespace but saying data: namespace div feels weird. Maybe namespaceTag?

Alternatives Considered

One alternative considered was to wrap patched elements individually in <svg> or <math> tags as a way to set their namespace, but this comes at a performance and memory cost since the wrapper elements persist in the document after patching. The cost of these wrapper elements can be significant when using SVG for data visualization since it's not uncommon to have thousands of elements (eg. circles in a scatterplot) that you might want to individually add/animate/remove.


Full proposal

The HTML spec specifies <svg> and <math> as the only allowed "foreign elements", and the namespace of children is determined by these parent tags.

The proposal is to add an optional patch-elements argument, wrap, which can be used to specify the name of a wrapper tag during element creation, allowing the namespace URI to be set while avoiding the costs associated with inserting wrapper elements into the document itself.

When using wrap Datastar will construct one extra wrapper element per patch call (which can of course patch multiple elements at once), which is in addition to the <body> and <template> elements that Datastar already typically creates. The wrapper element is never placed into the document and is only used to influence the namespaces of its children.

Examples:

event: datastar-patch-elements
data: mode append
data: selector #vis
data: wrap svg
data: elements <circle id="c1" cx="10" r="5" fill="red"/>
data: elements <circle id="c2" cx="20" r="5" fill="green"/>
data: elements <circle id="c3" cx="30" r="5" fill="blue"/>
event: datastar-patch-elements
data: selector #equation
data: mode inner
data: wrap math
data: elements <mi>x</mi><mo>=</mo><mfrac><mn>1</mn><mn>2</mn></mfrac>

Since elements can now be created in multiple namespaces, there is also a small change/bugfix to morphing to inherit the namespace from the existing element when creating a new empty child to morph into, ie. keeping the namespaces of any elements that already exist.

@yurivish yurivish force-pushed the svg-math-namespace branch 4 times, most recently from 088cc5a to 4814af5 Compare December 14, 2025 19:51
@bencroker
Copy link
Collaborator

This looks great! I made some minor tweaks for the sake of consistency.

@yurivish
Copy link
Contributor Author

yurivish commented Dec 14, 2025

@bencroker oops – sorry, I just force-pushed over your changes with a docs update 🤦‍♂️. Was using force push to keep the commit history clean. Can you please re-apply your changes?

Edit: Looks like I have them locally; applying…

@bencroker
Copy link
Collaborator

Having discussed it internally and reviewing the ADR changes, I think namespace would be more suitable than wrap, unless you see value in being able to wrap the elements in an arbitrary tag? The optional namespace option would accept a string enum 'html' | 'svg' | 'mathml', defaulting to html in patchElements.

@yurivish
Copy link
Contributor Author

I agree that's cleaner. How's this?

Replace the `wrap` property with a `namespace` property that accepts
a type-safe enum ('html' | 'svg' | 'mathml') instead of an arbitrary
tag name. The namespace defaults to 'html', matching the current
default behavior.

tidy

Tweak the description in the ADR

omit word

remove unneeded `as const`

ADR: for clarity, use backticks rather than quotes when enumerating possible values for the namespace option

update the namespace validity check to a form that typescript can use for narrowing

remove link to namespaceURI docs since the namespace option does not directly allow specifying namespaces (the connection can be elucidated in the user-facing docs)
@bencroker
Copy link
Collaborator

Much better! I refactored to use const arrays, and added a generic isValidType function that acts as a type guard, so that both PatchElementsMode and Namespace types can be checked in the same way. Any last tweaks you want to make?

@yurivish
Copy link
Contributor Author

yurivish commented Dec 15, 2025

Thanks, looks good to me. I just made two more tweaks, one prompted by a comment from @ecraven to allow the namespace option to be used with text/html responses, and another to update the sdk spec json files with the new option.

…1.json for the new namespace option

Update datastar-sdk-config-v1.json
@bencroker bencroker merged commit e1fd0ef into starfederation:develop Dec 15, 2025
@bencroker
Copy link
Collaborator

Added the namespace option to ResponseOverrides and merged. Excellent work, thank you!

@yurivish
Copy link
Contributor Author

🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants