Repository navigation
fix(compiler): read [class=…] from the prop the class list arrives on - #448
Open
YevheniiKotyrlo wants to merge 3 commits into
Open
YevheniiKotyrlo wants to merge 3 commits into
YevheniiKotyrlo wants to merge 3 commits into
Conversation
This was referenced Sep 10, 2026
Contributor
Author
react-native-web writes a dataSet entry as a data-* attribute for every value but null and undefined, so [data-x] matches data-x="false" in a browser. The runtime treated false as absent there, as it rightly does for a boolean prop, and compared an array value as no value, where the DOM holds its comma-joined text. HTML compares a dir value ASCII case-insensitively, so [dir="RTL"] matches dir="rtl" unless the selector carries the s flag. The compiler emitted the operand as written, and the direction condition never matched it. It now folds the operand unless s is given. Both folds share one ASCII lowercasing helper, which the runtime's i flag also uses.
The compound path and the :is() / :where() path each built the same query from an attribute selector, one with its own copy of the operator map. Both now call one builder.
React Native carries the class list as className, so an attribute query reading props.class answered false for every element, and [class~="x"], [class*="x"] and [class] never matched. The attribute builder maps class to className.
YevheniiKotyrlo
force-pushed
the
fix/class-attribute-selector
branch
from
October 11, 2026 12:35
ffe2a9a to
291ce56
Compare
This was referenced Oct 11, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
On
main,[class…]never matches. React Native carries the class list asclassName, but the attribute query readsprops.class, which no element has. So[class~="active"],[class*="act"],[class="a b"]and[class]answer false for every element, both on the element itself and on an ancestor.Solution
The compiler built an attribute query in two places, the compound path and the
:is()/:where()path, one of them with its own copy of the operator map. A first commit moves both onto one builder, with no change in behaviour. The second makes that builder readclassNameforclass.Tests
Every case renders as Chromium 153, Firefox 155 and WebKit 26.6 do.
src/__tests__/compiler/selectors.test.tsxcovers:=,~=,*=and presence compile to;[class~=…]through the:is()path;data-*and a plain attribute, as controls.src/__tests__/native/attributes.test.tsxrenders each operator over a class list, and an ancestor's class list with and without the class.:is()path unmapped.Verification
On Windows with Node 26:
yarn lintcleanyarn typecheckcleanyarn test --coverage: every failure also fails onmainon this machine (the four babel cases)yarn buildcleanyarn example expo export --platform webexportedMerge order
This builds on #447, which changes the same file and suites, so #447 lands first and this carries its commit until it does. #449 builds on this one.
It also shares lines with #462 (
compiler/selector-builder.ts); whichever lands second rebases.Base
Re-written on #447 (
55253748), which sits onmain(a5002c5).mainnamesaria-*attributes as written, and the builder keeps that.