You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In react-scan@0.5.7, overlay UI utilities that rely on Tailwind v4's translate / rotate / scale shorthand render incorrectly. The most visible symptom is the outline-render toggle switch: in the OFF state the white thumb pops out of the track and hangs below it. The same class of bug affects the resize handles, slider thumb, and expand arrow — anywhere the overlay CSS uses @apply -translate-* / translate-*.
Reproduction on Chrome 149 with a Tailwind v4 host (also reproduces with a non-Tailwind host, verified against a Panda CSS project — the host stylesheet is irrelevant since the overlay is inside a shadow DOM).
Downgrading to react-scan@0.5.6 restores correct rendering (v0.5.6 is on Tailwind v3, which uses preflight-seeded --tw-translate-* rather than @property).
Screenshots
Root cause
React Scan mounts its overlay UI in a shadow DOM and injects the bundled Tailwind stylesheet as a <style> element inside that shadow root (packages/scan/src/core/index.ts). Tailwind v3 → v4 in 0.5.7 changed how -translate-y-1/2 etc. compile: instead of the preflight-seeded --tw-translate-* variables, v4 emits 62 @property rules to declare the initial-value (0).
Chromium does not register @property rules declared inside a shadow-DOM stylesheet. The CSSOM parses them into CSSPropertyRules (visible via stylesheet.cssRules), but the custom-property registry is empty for that shadow tree. Consequently --tw-translate-x has no computed value, and
Measurement on .react-scan-toggle > div::before in the OFF state (react-scan 0.5.7, Chrome 149):
property
value
translate
none
--tw-translate-x
"" (empty)
--tw-translate-y
calc(calc(1 / 2 * 100%) * -1)
For the ON state, the input:checked + div::before selector applies translate-x-full which explicitly sets --tw-translate-x: 100%, so translate resolves — that's why the ON state visually looks OK while OFF is broken.
Document-level @property registrations do cascade into a shadow tree, verified in a minimal repro on Chrome 149.
Approach: in initRootContainer(), extract every @property --…{…} block from the bundled overlay CSS with a regex before injecting the stylesheet into the shadow root, and mount just those rules under a <style data-react-scan="property-registrations"> in document.head. The remainder still goes into the shadow root as before.
After the fix, the same ::before in the OFF state resolves to:
property
value
translate
0px -50%
--tw-translate-x
0
--tw-translate-y
calc(calc(1 / 2 * 100%) * -1)
and 62/62 @property rules move from the shadow tree to document.head.
Change is ~14 lines in packages/scan/src/core/index.ts plus a changeset entry
Manual verification in kitchen-sink on Chrome 149: toggle thumb renders centered in both OFF and ON states
Note
I tried to open this as a PR but hit "An owner of this repository has limited the ability to open a pull request to users that are collaborators on this repository." Happy to open the PR the moment the interaction limit is lifted, or invited as a collaborator, or feel free to cherry-pick the commit directly:
Related open work: PR #458 (React port of the toolbar UI) may incidentally sidestep this if it moves off Tailwind v4 utility classes, but it is still open and orthogonal.
Symptom
In
react-scan@0.5.7, overlay UI utilities that rely on Tailwind v4'stranslate/rotate/scaleshorthand render incorrectly. The most visible symptom is the outline-render toggle switch: in the OFF state the white thumb pops out of the track and hangs below it. The same class of bug affects the resize handles, slider thumb, and expand arrow — anywhere the overlay CSS uses@apply -translate-*/translate-*.Reproduction on Chrome 149 with a Tailwind v4 host (also reproduces with a non-Tailwind host, verified against a Panda CSS project — the host stylesheet is irrelevant since the overlay is inside a shadow DOM).
Downgrading to
react-scan@0.5.6restores correct rendering (v0.5.6 is on Tailwind v3, which uses preflight-seeded--tw-translate-*rather than@property).Screenshots
Root cause
React Scan mounts its overlay UI in a shadow DOM and injects the bundled Tailwind stylesheet as a
<style>element inside that shadow root (packages/scan/src/core/index.ts). Tailwind v3 → v4 in 0.5.7 changed how-translate-y-1/2etc. compile: instead of the preflight-seeded--tw-translate-*variables, v4 emits 62@propertyrules to declare theinitial-value(0).Chromium does not register
@propertyrules declared inside a shadow-DOM stylesheet. The CSSOM parses them intoCSSPropertyRules (visible viastylesheet.cssRules), but the custom-property registry is empty for that shadow tree. Consequently--tw-translate-xhas no computed value, andcollapses to
translate: none.Measurement on
.react-scan-toggle > div::beforein the OFF state (react-scan 0.5.7, Chrome 149):translatenone--tw-translate-x""(empty)--tw-translate-ycalc(calc(1 / 2 * 100%) * -1)For the ON state, the
input:checked + div::beforeselector appliestranslate-x-fullwhich explicitly sets--tw-translate-x: 100%, so translate resolves — that's why the ON state visually looks OK while OFF is broken.Document-level
@propertyregistrations do cascade into a shadow tree, verified in a minimal repro on Chrome 149.Spec: CSS Properties and Values API L1.
Proposed fix (branch available)
I have a one-file fix on my fork:
hidenari-pixel/react-scan@fix/shadow-dom-property-registration(diff)Approach: in
initRootContainer(), extract every@property --…{…}block from the bundled overlay CSS with a regex before injecting the stylesheet into the shadow root, and mount just those rules under a<style data-react-scan="property-registrations">indocument.head. The remainder still goes into the shadow root as before.After the fix, the same
::beforein the OFF state resolves to:translate0px -50%--tw-translate-x0--tw-translate-ycalc(calc(1 / 2 * 100%) * -1)and 62/62
@propertyrules move from the shadow tree todocument.head.packages/scan/src/core/index.tsplus a changeset entrypnpm --filter react-scan buildsucceedspnpm test:e2e— 47/47 pass, including the outline toggle instrumentation specs from test(e2e): deep Playwright coverage for the React Scan overlay UI #459kitchen-sinkon Chrome 149: toggle thumb renders centered in both OFF and ON statesNote
I tried to open this as a PR but hit "An owner of this repository has limited the ability to open a pull request to users that are collaborators on this repository." Happy to open the PR the moment the interaction limit is lifted, or invited as a collaborator, or feel free to cherry-pick the commit directly:
Related open work: PR #458 (React port of the toolbar UI) may incidentally sidestep this if it moves off Tailwind v4 utility classes, but it is still open and orthogonal.