From 0e6a46e287fa9393ad827077319ff57bd0a27f11 Mon Sep 17 00:00:00 2001 From: Wonsuk Choi Date: Thu, 28 May 2026 14:08:11 +0900 Subject: [PATCH] fix(query-devtools/utils): scope the 'setupStyleSheet' dedup check to the target so a 'shadowDOMTarget' still receives its own '#_goober' style tag when 'document.head' already has one --- .../devtools-setup-stylesheet-cross-target-dedup.md | 5 +++++ packages/query-devtools/src/__tests__/utils.test.ts | 13 +++++++++++++ packages/query-devtools/src/utils.tsx | 12 +++--------- 3 files changed, 21 insertions(+), 9 deletions(-) create mode 100644 .changeset/devtools-setup-stylesheet-cross-target-dedup.md diff --git a/.changeset/devtools-setup-stylesheet-cross-target-dedup.md b/.changeset/devtools-setup-stylesheet-cross-target-dedup.md new file mode 100644 index 0000000000..979db8513b --- /dev/null +++ b/.changeset/devtools-setup-stylesheet-cross-target-dedup.md @@ -0,0 +1,5 @@ +--- +'@tanstack/query-devtools': patch +--- + +fix(query-devtools/utils): scope the 'setupStyleSheet' dedup check to the target so a 'shadowDOMTarget' still receives its own '#_goober' style tag when 'document.head' already has one diff --git a/packages/query-devtools/src/__tests__/utils.test.ts b/packages/query-devtools/src/__tests__/utils.test.ts index 511553e2bb..e4a366e135 100644 --- a/packages/query-devtools/src/__tests__/utils.test.ts +++ b/packages/query-devtools/src/__tests__/utils.test.ts @@ -1042,6 +1042,19 @@ describe('Utils tests', () => { expect(styleTags).toHaveLength(1) expect(styleTags[0]?.getAttribute('nonce')).toBe('first-nonce') }) + + it('should install the style tag into the "ShadowRoot" target even when "document.head" already has one', () => { + const host = document.createElement('div') + const shadow = host.attachShadow({ mode: 'open' }) + + setupStyleSheet('host-nonce') + setupStyleSheet('shadow-nonce', shadow) + + expect(shadow.querySelector('#_goober')).not.toBeNull() + expect(shadow.querySelector('#_goober')?.getAttribute('nonce')).toBe( + 'shadow-nonce', + ) + }) }) describe('sortFns', () => { diff --git a/packages/query-devtools/src/utils.tsx b/packages/query-devtools/src/utils.tsx index 5306f2cf5f..44e7047d43 100644 --- a/packages/query-devtools/src/utils.tsx +++ b/packages/query-devtools/src/utils.tsx @@ -306,18 +306,12 @@ export const deleteNestedDataByPath = ( // Adds a nonce to the style tag if needed export const setupStyleSheet = (nonce?: string, target?: ShadowRoot) => { if (!nonce) return - const styleExists = - document.querySelector('#_goober') || target?.querySelector('#_goober') - - if (styleExists) return + const root = target ?? document.head + if (root.querySelector('#_goober')) return const styleTag = document.createElement('style') const textNode = document.createTextNode('') styleTag.appendChild(textNode) styleTag.id = '_goober' styleTag.setAttribute('nonce', nonce) - if (target) { - target.appendChild(styleTag) - } else { - document.head.appendChild(styleTag) - } + root.appendChild(styleTag) }