Skip to content

CSS: Use createElementNS to support XSLT documents#5775

Merged
mgol merged 4 commits intojquery:mainfrom
apoorvdarshan:fix/css-createElementNS-xslt-compat
Feb 23, 2026
Merged

CSS: Use createElementNS to support XSLT documents#5775
mgol merged 4 commits intojquery:mainfrom
apoorvdarshan:fix/css-createElementNS-xslt-compat

Conversation

@apoorvdarshan
Copy link
Contributor

@apoorvdarshan apoorvdarshan commented Feb 18, 2026

Summary

  • In XSLT-transformed documents, document.createElement("div").style is undefined because elements are created in the XML namespace rather than XHTML
  • Changed document.createElement to document.createElementNS("http://www.w3.org/1999/xhtml", ...) in src/css/finalPropName.js and src/css/support.js so that .style is always available
  • This is the fix recommended in the original issue discussion

Files changed

  • src/css/finalPropName.jsemptyStyle element creation now uses XHTML namespace
  • src/css/support.jstable, col, tr, td element creation now uses XHTML namespace (the table.style guard on line 19 already existed, but the root cause is the same)

How to reproduce the original bug

  1. Load a page via in-browser XSLT transformation
  2. In the console: document.createElement("div").styleundefined
  3. Compare: document.createElementNS("http://www.w3.org/1999/xhtml", "div").styleCSSStyleDeclaration

Fixes gh-4730

In XSLT-transformed documents, document.createElement("div").style
is undefined because elements are created in the XML namespace rather
than XHTML. Using document.createElementNS with the XHTML namespace
ensures .style is always available.

Ref jquerygh-4730
@linux-foundation-easycla
Copy link

linux-foundation-easycla bot commented Feb 18, 2026

CLA Signed

The committers listed above are authorized under a signed CLA.

Copy link
Member

@mgol mgol left a comment

Choose a reason for hiding this comment

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

Thanks for the PR. However, source changes are just a small part of what would be required to support XML documents, even on a basic level.

See my comment at #4730 (comment). Some infrastructure parts have changed, but you'd still need to modify mock.php & mockserver.js to support serving true XML documents and then define a few tests using them via testIframe. You can look at some tests already using testIframe to see how to use it; focus on the ones that pass mock.php?action=... as the URL.

Also, we have many more document.createElement usage, it seems we should replace them all? Or maybe create file ./src/var/createElement.js that would wrap the namespace logic? That'd also require measuring the size impact in both cases (running the build locally will tell you the sizes & the diff from a previous build).

Would you like to try that?

- Create src/var/createElement.js that wraps createElementNS with the
  XHTML namespace to support XSLT/XML documents where
  document.createElement creates elements without .style
- Replace all document.createElement calls in src/ with the helper
- Add mock server action (xmlCss) to serve XHTML as application/xml
- Add testIframe test verifying jQuery CSS works in XML documents

Size impact (minified): -170 bytes, gzipped: -6 bytes
The repeated namespace URI string is now centralized in one place.

Ref jquerygh-4730
@apoorvdarshan
Copy link
Contributor Author

Thanks for the review @mgol! I've pushed a follow-up commit addressing your feedback:

Changes

  1. Created src/var/createElement.js helper — Wraps document.createElementNS("http://www.w3.org/1999/xhtml", tag) so the namespace logic is centralized in one place.

  2. Replaced all document.createElement calls in src/ with the new helper:

    • src/ajax.js — 2 calls (anchor elements for URL parsing)
    • src/css/finalPropName.js — 1 call (was already using inline createElementNS)
    • src/css/support.js — 4 calls (were already using inline createElementNS)
  3. Added XML document test via testIframe — Serves an XHTML page as application/xml through a new xmlCss mock action (added to both mock.php and middleware-mockserver.cjs). The test verifies:

    • document.createElement("div").style is indeed undefined in the XML context (confirming the bug condition)
    • jQuery.css("width") still works correctly (confirming our fix)

Size impact

Before After Diff
jquery.js 256,155 256,282 +127
jquery.min.js 78,931 78,761 -170
jquery.min.js (gzip) 27,639 27,633 -6

The minified size actually decreased because the repeated "http://www.w3.org/1999/xhtml" namespace string is now only in one place.

All CSS, ajax, and support tests pass on both Chrome and Firefox.

@mgol
Copy link
Member

mgol commented Feb 18, 2026

The size impact table is comparing with the previous iteration, right? Against main it's a size increase:

main @7aa0179514a2aa9e1d90fbc6a4b332b8f1ae1292
   raw     gz     br Filename
   -17    +33    +20 dist/jquery.min.js
    +9    +40    +57 dist/jquery.slim.min.js
   -17    +34    +66 dist-module/jquery.module.min.js
    +9    +40    -27 dist-module/jquery.slim.module.min.js

@apoorvdarshan
Copy link
Contributor Author

You're right, the size table was comparing against the previous commit which already had inline createElementNS calls, not against main. Against main it's a net size increase as you showed. Thanks for clarifying!

Address review feedback:
- Remove redundant comment from xmlDocument.xhtml
- Use single var declaration in test scripts
- Wrap test code in try-catch, pass `threw` to startIframeTest
- Add XML document test for ajax cross-domain detection (jquerygh-4730)

Ref jquerygh-4730
@apoorvdarshan
Copy link
Contributor Author

Pushed a follow-up commit addressing the review feedback:

  1. Removed redundant comment from xmlDocument.xhtml
  2. Single var declaration in test scripts instead of multiple var statements
  3. Wrapped test code in try-catch, passing a threw parameter to startIframeTest so the test doesn't hang if jQuery crashes without the fix
  4. Added ajax cross-domain detection test (mock.php?action=xmlAjax) -- verifies that in an XML document, same-origin URLs are detected as same-origin and cross-origin URLs are detected as cross-domain

@mgol mgol added the Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. label Feb 18, 2026
- Uninitialized vars first, initialized last per style guide
- Drop empty line between assignments in CSS test
- Rename xmlDocument.xhtml to xmlDocCss.xhtml and
  xmlDocCrossDomainDetection.xhtml for unique names
- Update createElement.js comment to reference XML documents
  generally, not just XSLT

Ref jquerygh-4730
@apoorvdarshan
Copy link
Contributor Author

Pushed another commit addressing the latest feedback:

  1. Var ordering - uninitialized vars first, initialized (threw = false) last, applied to both test pages
  2. Dropped empty line between assignments in CSS test page
  3. Renamed files - xmlDocCss.xhtml and xmlDocCrossDomainDetection.xhtml for unique names
  4. Updated createElement.js comment to reference XML documents generally, not just XSLT

Copy link
Member

@mgol mgol left a comment

Choose a reason for hiding this comment

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

Thanks! This LGTM. I would not backport it to the 3.x-stable line as it has enough additional support tests that may cause more issues.

I want to discuss it with the team before merging, though, so please wait a bit more.

BTW, did you use AI to help with making the changes? I don't mind either way as the changes are high-quality and all my feedback was addressed; in the past, we've had issues with AI-submitted contributions that didn't make any sense, so that'd be the first for me here.

@apoorvdarshan
Copy link
Contributor Author

apoorvdarshan commented Feb 19, 2026

Thanks for the review! Happy to wait for the team discussion.

And yes, I used Claude Code (Opus 4.6) to assist with the changes.

@timmywil timmywil removed Needs review Discuss in Meeting Reserved for Issues and PRs that anyone would like to discuss in the weekly meeting. labels Feb 23, 2026
@mgol mgol added this to the 4.1.0 milestone Feb 23, 2026
@mgol mgol merged commit dcb31ae into jquery:main Feb 23, 2026
16 checks passed
@mgol
Copy link
Member

mgol commented Feb 23, 2026

Landed, thanks!

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

Labels

Development

Successfully merging this pull request may close these issues.

finalPropName.js: emptyStyle undefined for document generated by in-browser XSLT

4 participants