Skip to content

fix: match a dataSet value and a dir attribute the way the DOM does - #447

Open
YevheniiKotyrlo wants to merge 1 commit into
nativewind:mainfrom
YevheniiKotyrlo:fix/selectors-attribute-matching
Open

YevheniiKotyrlo wants to merge 1 commit into
nativewind:mainfrom
YevheniiKotyrlo:fix/selectors-attribute-matching

Conversation

@YevheniiKotyrlo

@YevheniiKotyrlo YevheniiKotyrlo commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor

Problem

On main:

  1. A false dataSet value is absent to [data-x]. react-native-web writes a dataSet entry as a data-* attribute for every value except null and undefined (createDOMProps), so [data-test] matches dataSet={{ test: false }} on the web. The runtime treats false as absent there, as it rightly does for a boolean prop such as disabled.
  2. An array dataSet value compares as no value. The DOM holds the array's comma-joined text, so [data-test="a,b"] matches dataSet={{ test: ["a", "b"] }}.
  3. [dir="RTL"] never matches. HTML compares a dir value ASCII case-insensitively, so the selector matches dir="rtl" unless it carries the s flag. The compiler emits the operand as written, and the direction condition compares it literally.

Solution

  • dataSet values. A dataSet value is present unless it is nullish, and it compares as the text the DOM holds. A plain prop keeps its boolean-attribute rule, so false is still absent there.
  • dir operands. The compiler folds a dir operand to lowercase unless the selector carries s.
  • Shared ASCII folding. Both folds use one ASCII lowercasing helper, which the runtime's i flag also uses. toLowerCase would also fold U+212A KELVIN SIGN onto k.

Tests

Every case renders as Chromium 153, Firefox 155 and WebKit 26.6 do.

  • src/__tests__/native/attributes.test.tsx:
    • [data-test] over false, 0, "", null and undefined;
    • [disabled] over a false prop;
    • = and ~= over an array value.
  • src/__tests__/compiler/selectors.test.tsx covers the condition [dir=…] compiles to, in each case and with the i and s flags.
  • src/__tests__/native/direction-media.test.tsx renders [dir="RTL"], [dir="RTL" i] and [dir="RTL" s] against a right-to-left layout.
  • On main, 7 of the 45 cases in these files fail. Each of 7 mutations fails its own cases.

Verification

On Windows with Node 26:

  • yarn lint clean
  • yarn typecheck clean
  • yarn test --coverage: every failure also fails on main on this machine (the four babel cases)
  • yarn build clean
  • yarn example expo export --platform web exported

Merge order

Base

Re-written on main (a5002c5). #451 already answers the rest of Selectors §6 the way this PR did on its old base: exact comparison, whitespace and dash-match boundaries, the empty-operand exclusions and the i flag. Its tests cover those, so this PR no longer carries them.

@YevheniiKotyrlo

YevheniiKotyrlo commented Sep 10, 2026 •

Copy link
Copy Markdown
Contributor Author

No current device pair

Every build of my test app carries this change: the app's reading-direction code needs #459, which is built on #447, #448 and #449. So no build can show the before, and the description's tests are the evidence.

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.
@YevheniiKotyrlo
YevheniiKotyrlo force-pushed the fix/selectors-attribute-matching branch from f910a68 to 5525374 Compare October 11, 2026 12:35
@YevheniiKotyrlo YevheniiKotyrlo changed the title fix(native): answer an attribute selector the way Selectors §6 defines it fix: match a dataSet value and a dir attribute the way the DOM does Oct 11, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant