Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

HTML children of <foreignObject> are created in the SVG namespace on the client, so they don't render

オープン 初心者向け
#106 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 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 を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

TanStack/redact のほかの issue

TanStack/redact の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。