Skip to content

Allow outline* styles on stable React Native#493

Open
MoOx wants to merge 1 commit into
react:mainfrom
MoOx:outline-fix-467
Open

Allow outline* styles on stable React Native#493
MoOx wants to merge 1 commit into
react:mainfrom
MoOx:outline-fix-467

Conversation

@MoOx

@MoOx MoOx commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

Closes #467

Root cause

The outlineColor/outlineOffset/outlineStyle/outlineWidth keys were gated behind version.experimental in isAllowedStyleKey.js (and outlineOffset/outlineWidth in isLengthStyleKey.js). Any style key not in the allow-list is silently dropped, so these props never reached React Native on a published release.

version.experimental is not a user-facing flag. It is derived from the RN version at runtime

https://github.com/facebook/react-strict-dom/blob/c4e69e0fa486ba8df835a2e3f396206070c17153/packages/react-strict-dom/src/native/modules/version.js#L13-L20

It is true only on HEAD/nightly builds and false on every published RN release (e.g. 0.84.0). So the documented outline* support was unreachable for normal apps, with no way to opt in.

Why it was a stale gate

The outline* keys were originally added alongside boxShadow, filter, and mixBlendMode in the same experimental block. Those three were later graduated into the always-allowed set; the four outline* keys were left behind by oversight. RN has supported outline* since 0.77, and RSD's minimum is react-native >=0.82.0, so the props are safe to allow unconditionally for every supported version.

Why tests didn't catch it

The test suite mocks the RN version as major: 1000 (tests/__mocks__/react-native/index.js), which forces experimental === true. The existing outline* test therefore passed in CI while the same code dropped the props for users on stable RN.

The fix

Graduated the keys out of the experimental gate (same treatment already given to boxShadow/filter/mixBlendMode):

  • isAllowedStyleKey.js — moved outlineColor, outlineOffset, outlineStyle, outlineWidth into the main allow-list; removed the now-empty if (version.experimental) block and its unused version import.
  • isLengthStyleKey.js — moved outlineOffset, outlineWidth into the main length-key set; removed the experimental block and unused import.

Result

outline* now resolves on all supported RN versions, the documentation becomes accurate with no changes, the existing test now exercises the real (non-experimental) path, Flow passes, and the full CSS suite (141 tests) is green.

Closes react#467

## Root cause

The `outlineColor`/`outlineOffset`/`outlineStyle`/`outlineWidth` keys were gated behind `version.experimental` in `isAllowedStyleKey.js` (and `outlineOffset`/`outlineWidth` in `isLengthStyleKey.js`). Any style key not in the allow-list is silently dropped, so these props never reached React Native on a published release.

`version.experimental` is **not** a user-facing flag. It is derived from the RN version at runtime

https://github.com/facebook/react-strict-dom/blob/c4e69e0fa486ba8df835a2e3f396206070c17153/packages/react-strict-dom/src/native/modules/version.js#L13-L20

It is `true` **only** on HEAD/nightly builds and `false` on every published RN release (e.g. 0.84.0). So the documented `outline*` support was unreachable for normal apps, with no way to opt in.

## Why it was a stale gate

The `outline*` keys were originally added alongside `boxShadow`, `filter`, and `mixBlendMode` in the same experimental block. Those three were later graduated into the always-allowed set; the four `outline*` keys were left behind by oversight. RN has supported `outline*` since 0.77, and RSD's minimum is `react-native >=0.82.0`, so the props are safe to allow unconditionally for every supported version.

## Why tests didn't catch it

The test suite mocks the RN version as `major: 1000` (`tests/__mocks__/react-native/index.js`), which forces `experimental === true`. The existing `outline*` test therefore passed in CI while the same code dropped the props for users on stable RN.

## The fix

Graduated the keys out of the experimental gate (same treatment already given to `boxShadow`/`filter`/`mixBlendMode`):

- `isAllowedStyleKey.js` — moved `outlineColor`, `outlineOffset`, `outlineStyle`, `outlineWidth` into the main allow-list; removed the now-empty `if (version.experimental)` block and its unused `version` import.
- `isLengthStyleKey.js` — moved `outlineOffset`, `outlineWidth` into the main length-key set; removed the experimental block and unused import.

## Result

`outline*` now resolves on all supported RN versions, the documentation becomes accurate with no changes, the existing test now exercises the real (non-experimental) path, Flow passes, and the full CSS suite (141 tests) is green.
Copilot AI review requested due to automatic review settings June 1, 2026 14:10
@meta-cla meta-cla Bot added the cla signed label Jun 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR makes outline* CSS properties unconditionally allowed/handled in the native CSS style-key sets by removing the previous version.experimental gating.

Changes:

  • Removed version import and the associated version.experimental conditional blocks in style-key set definitions.
  • Added outlineOffset/outlineWidth to the length style key set unconditionally.
  • Added outlineColor/outlineOffset/outlineStyle/outlineWidth to the allowed style key set unconditionally.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
packages/react-strict-dom/src/native/css/isLengthStyleKey.js Makes outlineOffset/outlineWidth always treated as length-valued style keys by moving them into the static set.
packages/react-strict-dom/src/native/css/isAllowedStyleKey.js Makes outline* properties always considered allowed style keys by moving them into the static set.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +123 to +126
'outlineColor',
'outlineOffset',
'outlineStyle',
'outlineWidth',
Comment on lines +66 to +67
'outlineOffset',
'outlineWidth',
@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

workflow: benchmarks/size

Comparison of minified (terser) and compressed (brotli) size results, measured in bytes. Smaller is better.

Results Base Patch Ratio
react-strict-dom/dist/web/index.js
· compressed 3,251 3,251 1.00
· minified 10,375 10,375 1.00
react-strict-dom/dist/web/runtime.js
· compressed 1,645 1,645 1.00
· minified 4,131 4,131 1.00
react-strict-dom/dist/native/index.js
· compressed 16,618 16,495 0.99 -
· minified 64,626 64,135 0.99 -
react-strict-animated/dist/web/index.js
· compressed 6,861 6,861 1.00
· minified 23,486 23,486 1.00
react-strict-animated/dist/native/index.js
· compressed 797 797 1.00
· minified 2,518 2,518 1.00

@github-actions

github-actions Bot commented Jun 1, 2026

Copy link
Copy Markdown

workflow: benchmarks/perf (native)

Comparison of performance test results, measured in operations per second. Larger is better.

Results Base Patch Ratio
css.create
· small 1,142,540 1,188,524 1.04 +
· small with units 506,704 494,209 0.98 -
· small with variables 678,302 702,948 1.04 +
· several small 362,616 357,747 0.99 -
· large 211,717 206,565 0.98 -
· large with polyfills 160,136 156,528 0.98 -
· complex 111,407 109,418 0.98 -
· unsupported 219,754 215,474 0.98 -
css.createTheme
· simple theme 243,620 245,105 1.01 +
· polyfill theme 231,077 232,473 1.01 +

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Outline styles aren't parsed in React Native

2 participants