HTML children of <foreignObject> are created in the SVG namespace on the client, so they don't render
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 85/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- react, typescript
- 領域
- frontend
調査の方向性
packages/redact/src/dom/reconcile.ts の renderHost() から始め、名前空間の選択を features/hydration/full.ts の hydration ケースと比較してください。提供された jsdom スクリプトで再現し、foreignObject 内の div と span の名前空間を確認してください。クライアントレンダリングでこれらの HTML 子要素が XHTML 名前空間に配置され、React の出力と一致すれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Version: @tanstack/redact 0.2.2, renderHost() unchanged on main (47f206ea). Baseline: react / react-dom 19.3.1.
On the client, renderHost() in packages/redact/src/dom/reconcile.ts creates an element in the SVG namespace whenever its DOM parent is in the SVG namespace:
const isSvg = type === 'svg' || (domParent as Element).namespaceURI === 'http://www.w3.org/2000/svg';
<foreignObject> is itself an SVG element, so its HTML children (<div>, <span>, …) are created with createElementNS(SVG_NS, 'div'). The browser treats them as unknown SVG elements and draws nothing. React switches back to the HTML namespace inside foreignObject. The hydration path already has this case (tag !== 'foreignobject' in features/hydration/full.ts); the client render path doesn't.
We hit it on a badge that draws an emoji as an HTML <div> inside a <foreignObject>. The SVG frame renders, and the emoji is missing.
Reproduction
npm i @tanstack/[email protected] [email protected] [email protected] jsdom, then node repro.mjs react and node repro.mjs redact:
// repro.mjs
import { JSDOM } from "jsdom"
const { window } = new JSDOM("<!doctype html><div id=root></div>")
Object.assign(globalThis, { window, document: window.document, HTMLElement: window.HTMLElement, Node: window.Node })
const redact = process.argv[2] === "redact"
const R = await import(redact ? "@tanstack/redact" : "react")
const { createRoot } = await import(redact ? "@tanstack/redact/dom-client" : "react-dom/client")
const { flushSync } = await import(redact ? "@tanstack/redact/dom" : "react-dom")
const h = R.createElement
const App = () =>
h("svg", { viewBox: "0 0 100 100" },
h("foreignObject", { width: 100, height: 100 },
h("div", null, h("span", null, "🦔"))))
const root = document.getElementById("root")
flushSync(() => createRoot(root).render(h(App)))
for (const tag of ["foreignObject", "div", "span"]) {
console.log(tag.padEnd(14), root.querySelector(tag).namespaceURI)
}
| Element | React 19.3.1 | Redact 0.2.2 |
|---|---|---|
foreignObject |
http://www.w3.org/2000/svg |
http://www.w3.org/2000/svg |
div |
http://www.w3.org/1999/xhtml |
http://www.w3.org/2000/svg |
span |
http://www.w3.org/1999/xhtml |
http://www.w3.org/2000/svg |
Suggested fix
Leave the SVG namespace when the DOM parent is a foreignObject:
const isSvg = type === 'svg' ||
((domParent as Element).namespaceURI === 'http://www.w3.org/2000/svg' &&
(domParent as Element).localName !== 'foreignObject');
We run this as a local patch and the emoji renders again.
- 主要言語
- TypeScript
- スター
- 408
- フォーク
- 13
- 平均マージ
- 1時間 44分
- マージ済み PR(30日)
- 21
環境構築
このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
TanStack/redact のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 90/100
TanStack/redact#67 · リアクション 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
TanStack/redact#58 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
TanStack/redact の issue をすべて見る
似ている issue
-
area:desktop area:ui bug platform:macos
難易度 2/5 1〜3時間 初心者へのやさしさ 67/100
anthropics/claude-code#106183 ·
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1〜3時間 初心者へのやさしさ 76/100
メンテナーはふだん 1 日以内に返信
-
feature:App-Tour feature:Chat ready Web
難易度 2/5 1〜3時間 初心者へのやさしさ 62/100
digitalfabrik/integreat-app#4523 · リアクション 2 件 ·
メンテナーはふだん 3 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
Required Lexical field accepts two empty paragraphs対応中かも @lazerg が今日担当しました。 オープンBug
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
payloadcms/payload#19222 ·
メンテナーはふだん 1 日以内に返信