Skip to content

RFC: Raw color fallback for PlatformColor - #1008

Open
Abbondanzo wants to merge 3 commits into
react-native-community:mainfrom
Abbondanzo:abbo/raw-colors
Open

RFC: Raw color fallback for PlatformColor#1008
Abbondanzo wants to merge 3 commits into
react-native-community:mainfrom
Abbondanzo:abbo/raw-colors

Conversation

@Abbondanzo

@Abbondanzo Abbondanzo commented Jul 8, 2026

Copy link
Copy Markdown

This adds a short RFC for introducing an API change to PlatformColor that allows fallbacks, rather than rendering transparently

RFC Document

Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 22, 2026
Summary:
Pull Request resolved: react#57556

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

PlatformColor previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to the native layer as a raw, unprocessed string and is only parsed when every provided token fails to resolve. When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

The change spans the JS entry points (all platform `PlatformColorValueTypes.*` files plus the Flow and TypeScript type declarations), the iOS (Paper and Fabric) and Android (Paper and Fabric) native color resolvers, a new "Lazy Fallback Colors" section in the RNTester PlatformColor example, and the regenerated C++ API snapshots.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Differential Revision: D111837102
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 23, 2026
…cOS (native) (react#57556)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

This is the first diff in a stack that adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to native and parsed only when every supplied color token fails to resolve. This diff wires up the iOS and macOS native color resolvers to honor that fallback; a later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.

To distinguish a genuine miss (no token resolves) from a token that legitimately resolves to a transparent color, the semantic-color resolver gains an `OrNil` variant:

- `RCTPlatformColorFromSemanticItemsOrNil` returns `nil` on a miss instead of collapsing to `clearColor`. `RCTPlatformColorFromSemanticItems` keeps its existing non-null contract by wrapping the `OrNil` variant.
- On Fabric, `Color::createSemanticColor` returns the undefined-color sentinel (a null underlying `UIColor`) on a miss, so `PlatformColorParser.mm` can apply the fallback only on a true miss and otherwise render transparent exactly as before.
- The fallback string is parsed with the shared CSS color parser (`parseCSSProperty<CSSColor>`), so `transparent`/`rgba(0,0,0,0)` are honored rather than mistaken for a parse failure.
- On the iOS Paper (legacy) path, `RCTConvert.mm` parses the common hex forms (`#RGB`, `#RGBA`, `#RRGGBB`, `#RRGGBBAA`, alpha last) as the fallback when every semantic name misses.

This spans the `xplat` iOS/macOS graphics resolvers and the vendored `third-party/react-native-macos` copies.

Changelog:
[Internal] - PlatformColor: iOS/macOS native support for a lazy raw-color fallback

Differential Revision: D111837102
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…cOS (native) (react#57556)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

This is the first diff in a stack that adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to native and parsed only when every supplied color token fails to resolve. This diff wires up the iOS and macOS native color resolvers to honor that fallback; a later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites. The fallback is supported on the new architecture (Fabric) only.

To distinguish a genuine miss (no token resolves) from a token that legitimately resolves to a transparent color, the semantic-color resolver gains an `OrNil` variant:

- `RCTPlatformColorFromSemanticItemsOrNil` returns `nil` on a miss instead of collapsing to `clearColor`. `RCTPlatformColorFromSemanticItems` keeps its existing non-null contract by wrapping the `OrNil` variant.
- `Color::createSemanticColor` returns the undefined-color sentinel (a null underlying `UIColor`) on a miss, so `PlatformColorParser.mm` applies the fallback only on a true miss and otherwise renders transparent exactly as before.
- The fallback string is parsed with the shared CSS color parser (`parseCSSProperty<CSSColor>`), so `transparent`/`rgba(0,0,0,0)` are honored rather than mistaken for a parse failure.

This spans the `xplat` iOS and macOS graphics resolvers.

Changelog:
[Internal] - PlatformColor: iOS/macOS native support for a lazy raw-color fallback

Reviewed By: javache

Differential Revision: D111837102
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…ative) (react#57655)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Wires up the Android native color resolver (Fabric) to honor the lazy `{fallback}` carried by `PlatformColor(...)`. A later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.

To tell a genuine miss apart from a token that resolves to transparent black (ARGB 0):

- `FabricUIManager.getColor` now returns a boxed `Nullable Integer` — `null` means no resource path resolved. The Fabric C++ `PlatformColorParser.h` reads that boxed result over JNI, caches the explicit-miss signal, and on a miss parses the raw fallback string with the shared CSS color parser (`parseCSSProperty<CSSColor>`), matching the iOS Fabric path. The color object is now read as a `map<string, RawValue>` because it mixes an array (`resource_paths`) with an optional string (`fallback`).
- `NativeDrawable` carries an optional `colorFallback` alongside `resource_paths` so ripple drawables degrade to the fallback too.

Generated files (`ReactAndroid.api` and the `ReactAndroid*Cxx.api` snapshots) are regenerated to match the new public signatures.

Changelog:
[Internal] - PlatformColor: Android native support for a lazy raw-color fallback

Reviewed By: mdvacca

Differential Revision: D113329136
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…cOS (native) (react#57556)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

This is the first diff in a stack that adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to native and parsed only when every supplied color token fails to resolve. This diff wires up the iOS and macOS native color resolvers to honor that fallback; a later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites. The fallback is supported on the new architecture (Fabric) only.

To distinguish a genuine miss (no token resolves) from a token that legitimately resolves to a transparent color, the semantic-color resolver gains an `OrNil` variant:

- `RCTPlatformColorFromSemanticItemsOrNil` returns `nil` on a miss instead of collapsing to `clearColor`. `RCTPlatformColorFromSemanticItems` keeps its existing non-null contract by wrapping the `OrNil` variant.
- `Color::createSemanticColor` returns the undefined-color sentinel (a null underlying `UIColor`) on a miss, so `PlatformColorParser.mm` applies the fallback only on a true miss and otherwise renders transparent exactly as before.
- The fallback string is parsed with the shared CSS color parser (`parseCSSProperty<CSSColor>`), so `transparent`/`rgba(0,0,0,0)` are honored rather than mistaken for a parse failure.

This spans the `xplat` iOS and macOS graphics resolvers.

Changelog:
[Internal] - PlatformColor: iOS/macOS native support for a lazy raw-color fallback

Reviewed By: javache

Differential Revision: D111837102
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…ative) (react#57655)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Wires up the Android native color resolver (Fabric) to honor the lazy `{fallback}` carried by `PlatformColor(...)`. A later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.

To tell a genuine miss apart from a token that resolves to transparent black (ARGB 0):

- `FabricUIManager.getColor` now returns a boxed `Nullable Integer` — `null` means no resource path resolved. The Fabric C++ `PlatformColorParser.h` reads that boxed result over JNI, caches the explicit-miss signal, and on a miss parses the raw fallback string with the shared CSS color parser (`parseCSSProperty<CSSColor>`), matching the iOS Fabric path. The color object is now read as a `map<string, RawValue>` because it mixes an array (`resource_paths`) with an optional string (`fallback`).
- `NativeDrawable` carries an optional `colorFallback` alongside `resource_paths` so ripple drawables degrade to the fallback too.

Generated files (`ReactAndroid.api` and the `ReactAndroid*Cxx.api` snapshots) are regenerated to match the new public signatures.

Changelog:
[Internal] - PlatformColor: Android native support for a lazy raw-color fallback

Reviewed By: mdvacca, javache

Differential Revision: D113329136
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…cOS (native) (react#57556)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

This is the first diff in a stack that adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to native and parsed only when every supplied color token fails to resolve. This diff wires up the iOS and macOS native color resolvers to honor that fallback; a later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites. The fallback is supported on the new architecture (Fabric) only.

To distinguish a genuine miss (no token resolves) from a token that legitimately resolves to a transparent color, the semantic-color resolver gains an `OrNil` variant:

- `RCTPlatformColorFromSemanticItemsOrNil` returns `nil` on a miss instead of collapsing to `clearColor`. `RCTPlatformColorFromSemanticItems` keeps its existing non-null contract by wrapping the `OrNil` variant.
- `Color::createSemanticColor` returns the undefined-color sentinel (a null underlying `UIColor`) on a miss, so `PlatformColorParser.mm` applies the fallback only on a true miss and otherwise renders transparent exactly as before.
- The fallback string is parsed with the shared CSS color parser (`parseCSSProperty<CSSColor>`), so `transparent`/`rgba(0,0,0,0)` are honored rather than mistaken for a parse failure.

This spans the `xplat` iOS and macOS graphics resolvers.

Changelog:
[Internal] - PlatformColor: iOS/macOS native support for a lazy raw-color fallback

Reviewed By: javache

Differential Revision: D111837102
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…ative) (react#57655)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Wires up the Android native color resolver (Fabric) to honor the lazy `{fallback}` carried by `PlatformColor(...)`. A later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.

To tell a genuine miss apart from a token that resolves to transparent black (ARGB 0):

- `FabricUIManager.getColor` now returns a boxed `Nullable Integer` — `null` means no resource path resolved. The Fabric C++ `PlatformColorParser.h` reads that boxed result over JNI, caches the explicit-miss signal, and on a miss parses the raw fallback string with the shared CSS color parser (`parseCSSProperty<CSSColor>`), matching the iOS Fabric path. The color object is now read as a `map<string, RawValue>` because it mixes an array (`resource_paths`) with an optional string (`fallback`).
- `NativeDrawable` carries an optional `colorFallback` alongside `resource_paths` so ripple drawables degrade to the fallback too.

Generated files (`ReactAndroid.api` and the `ReactAndroid*Cxx.api` snapshots) are regenerated to match the new public signatures.

Changelog:
[Internal] - PlatformColor: Android native support for a lazy raw-color fallback

Reviewed By: mdvacca, javache

Differential Revision: D113329136
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…cOS (native) (react#57556)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

This is the first diff in a stack that adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to native and parsed only when every supplied color token fails to resolve. This diff wires up the iOS and macOS native color resolvers to honor that fallback; a later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites. The fallback is supported on the new architecture (Fabric) only.

To distinguish a genuine miss (no token resolves) from a token that legitimately resolves to a transparent color, the semantic-color resolver gains an `OrNil` variant:

- `RCTPlatformColorFromSemanticItemsOrNil` returns `nil` on a miss instead of collapsing to `clearColor`. `RCTPlatformColorFromSemanticItems` keeps its existing non-null contract by wrapping the `OrNil` variant.
- `Color::createSemanticColor` returns the undefined-color sentinel (a null underlying `UIColor`) on a miss, so `PlatformColorParser.mm` applies the fallback only on a true miss and otherwise renders transparent exactly as before.
- The fallback string is parsed with the shared CSS color parser (`parseCSSProperty<CSSColor>`), so `transparent`/`rgba(0,0,0,0)` are honored rather than mistaken for a parse failure.

This spans the `xplat` iOS and macOS graphics resolvers.

Changelog:
[Internal] - PlatformColor: iOS/macOS native support for a lazy raw-color fallback

Reviewed By: javache

Differential Revision: D111837102
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
…ative) (react#57655)

Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Wires up the Android native color resolver (Fabric) to honor the lazy `{fallback}` carried by `PlatformColor(...)`. A later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.

To tell a genuine miss apart from a token that resolves to transparent black (ARGB 0):

- `FabricUIManager.getColor` now returns a boxed `Nullable Integer` — `null` means no resource path resolved. The Fabric C++ `PlatformColorParser.h` reads that boxed result over JNI, caches the explicit-miss signal, and on a miss parses the raw fallback string with the shared CSS color parser (`parseCSSProperty<CSSColor>`), matching the iOS Fabric path. The color object is now read as a `map<string, RawValue>` because it mixes an array (`resource_paths`) with an optional string (`fallback`).
- `NativeDrawable` carries an optional `colorFallback` alongside `resource_paths` so ripple drawables degrade to the fallback too.

Generated files (`ReactAndroid.api` and the `ReactAndroid*Cxx.api` snapshots) are regenerated to match the new public signatures.

Changelog:
[Internal] - PlatformColor: Android native support for a lazy raw-color fallback

Reviewed By: mdvacca, javache

Differential Revision: D113329136
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 27, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Rounds out the lazy `PlatformColor` fallback with tooling and a demo.

- The `react-native/platform-colors` ESLint rule now permits an optional trailing `{fallback: <literal>}` options object so `PlatformColor('token', {fallback: '#RRGGBB'})` is lint-clean, while still requiring every other argument to be a literal. The options object must have exactly one `fallback` property whose value is a literal, so it stays statically analyzable.
- A new "Lazy Fallback Colors" section in the RNTester `PlatformColor` example demonstrates valid tokens, misses with no fallback (transparent), and misses with hex / `rgb()` / `rgba()` / `#RRGGBBAA` fallbacks across `backgroundColor`, text `color`, and `borderColor`.

Changelog:
[Internal] - PlatformColor: ESLint support and RNTester example for the lazy raw-color fallback

Differential Revision: D113329138
meta-codesync Bot pushed a commit to react/react-native that referenced this pull request Jul 28, 2026
…cOS (native) (#57556)

Summary:
Pull Request resolved: #57556

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

This is the first diff in a stack that adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)`. The fallback is carried lazily to native and parsed only when every supplied color token fails to resolve. This diff wires up the iOS and macOS native color resolvers to honor that fallback; a later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites. The fallback is supported on the new architecture (Fabric) only.

To distinguish a genuine miss (no token resolves) from a token that legitimately resolves to a transparent color, the semantic-color resolver gains an `OrNil` variant:

- `RCTPlatformColorFromSemanticItemsOrNil` returns `nil` on a miss instead of collapsing to `clearColor`. `RCTPlatformColorFromSemanticItems` keeps its existing non-null contract by wrapping the `OrNil` variant.
- `Color::createSemanticColor` returns the undefined-color sentinel (a null underlying `UIColor`) on a miss, so `PlatformColorParser.mm` applies the fallback only on a true miss and otherwise renders transparent exactly as before.
- The fallback string is parsed with the shared CSS color parser (`parseCSSProperty<CSSColor>`), so `transparent`/`rgba(0,0,0,0)` are honored rather than mistaken for a parse failure.

This spans the `xplat` iOS and macOS graphics resolvers.

Changelog:
[Internal] - PlatformColor: iOS/macOS native support for a lazy raw-color fallback

Reviewed By: javache, cipolleschi

Differential Revision: D111837102

fbshipit-source-id: 20fd1d6e10b1ce953de3644752051843b51b230f
meta-codesync Bot pushed a commit to react/react-native that referenced this pull request Jul 28, 2026
…ative) (#57655)

Summary:
Pull Request resolved: #57655

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Wires up the Android native color resolver (Fabric) to honor the lazy `{fallback}` carried by `PlatformColor(...)`. A later diff adds the JS argument that emits it, so on its own this change is a no-op for existing call sites.

To tell a genuine miss apart from a token that resolves to transparent black (ARGB 0):

- `FabricUIManager.getColor` now returns a boxed `Nullable Integer` — `null` means no resource path resolved. The Fabric C++ `PlatformColorParser.h` reads that boxed result over JNI, caches the explicit-miss signal, and on a miss parses the raw fallback string with the shared CSS color parser (`parseCSSProperty<CSSColor>`), matching the iOS Fabric path. The color object is now read as a `map<string, RawValue>` because it mixes an array (`resource_paths`) with an optional string (`fallback`).
- `NativeDrawable` carries an optional `colorFallback` alongside `resource_paths` so ripple drawables degrade to the fallback too.

Generated files (`ReactAndroid.api` and the `ReactAndroid*Cxx.api` snapshots) are regenerated to match the new public signatures.

Changelog:
[Internal] - PlatformColor: Android native support for a lazy raw-color fallback

Reviewed By: mdvacca, javache

Differential Revision: D113329136

fbshipit-source-id: ee15aea8dfed66364e99d427825e1b9ebcbdc483
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 29, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Jul 30, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Reviewed By: javache, huntie

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Rounds out the lazy `PlatformColor` fallback with tooling and a demo.

- The `react-native/platform-colors` ESLint rule now permits an optional trailing `{fallback: <literal>}` options object so `PlatformColor('token', {fallback: '#RRGGBB'})` is lint-clean, while still requiring every other argument to be a literal. The options object must have exactly one `fallback` property whose value is a literal, so it stays statically analyzable.
- A new "Lazy Fallback Colors" section in the RNTester `PlatformColor` example demonstrates valid tokens, misses with no fallback (transparent), and misses with hex / `rgb()` / `rgba()` / `#RRGGBBAA` fallbacks across `backgroundColor`, text `color`, and `borderColor`.

Changelog:
[Internal] - PlatformColor: ESLint support and RNTester example for the lazy raw-color fallback

Reviewed By: christophpurrer

Differential Revision: D113329138
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Reviewed By: javache, huntie

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Rounds out the lazy `PlatformColor` fallback with tooling and a demo.

- The `react-native/platform-colors` ESLint rule now permits an optional trailing `{fallback: <literal>}` options object so `PlatformColor('token', {fallback: '#RRGGBB'})` is lint-clean, while still requiring every other argument to be a literal. The options object must have exactly one `fallback` property whose value is a literal, so it stays statically analyzable.
- A new "Lazy Fallback Colors" section in the RNTester `PlatformColor` example demonstrates valid tokens, misses with no fallback (transparent), and misses with hex / `rgb()` / `rgba()` / `#RRGGBBAA` fallbacks across `backgroundColor`, text `color`, and `borderColor`.

Changelog:
[Internal] - PlatformColor: ESLint support and RNTester example for the lazy raw-color fallback

Reviewed By: christophpurrer

Differential Revision: D113329138
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Adds unit and integration coverage for the PlatformColor raw-color fallback introduced in the parent diff:
- CSSColorTest.cpp: additional CSS `<color>` parse cases pinning the shared parser used on the native fallback path
- PlatformColorFallback-itest.js: JS integration test for token-miss -> fallback

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D111917092
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Reviewed By: javache, huntie

Differential Revision: D113329139
Abbondanzo added a commit to Abbondanzo/react-native that referenced this pull request Aug 5, 2026
Summary:

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Reviewed By: javache, huntie

Differential Revision: D113329139
meta-codesync Bot pushed a commit to react/react-native that referenced this pull request Aug 6, 2026
Summary:
Pull Request resolved: #57701

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

`PlatformColor` previously had no way to specify what color to use when none of the supplied native color tokens resolve on the device. On a miss the behavior was inconsistent across platforms and architectures (transparent, nil, or a thrown error), giving apps no control over the rendered result.

This adds an optional trailing `{fallback: '<raw color string>'}` argument to `PlatformColor(...)` and updates the JS entry points to emit it. The fallback is carried lazily to native as a raw, unprocessed string and is only parsed when every provided token fails to resolve (the native side of that behavior landed earlier in this stack). When at least one token resolves the fallback is ignored, so existing call sites are completely unaffected and omitting the argument preserves today's exact behavior.

Example:

  PlatformColor('someSystemToken', {fallback: '#FF0000'})

Each platform entry point (`PlatformColorValueTypes.{android,ios,macos,windows}.js`, plus the vendored macOS/Windows copies) collects the leading string tokens and, when a trailing `{fallback}` object is present, attaches its raw string to the native color object. Non-string arguments in a non-trailing position are filtered out consistently rather than being forwarded to native. The Flow (`.js.flow`), TypeScript (`.d.ts`), and generated (`ReactNativeApi.d.ts`) declarations widen the signature to `Array<string | {fallback: string}>`, which is backward compatible.

Changelog:
[General][Added] - Support a lazy raw color fallback for PlatformColor when native tokens fail to resolve

Reviewed By: javache, huntie

Differential Revision: D113329139

fbshipit-source-id: b6eb16e34d708bf8c14f8a8e3b9eb70547245447
meta-codesync Bot pushed a commit to react/react-native that referenced this pull request Aug 6, 2026
Summary:
Pull Request resolved: #57705

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Rounds out the lazy `PlatformColor` fallback with tooling and a demo.

- The `react-native/platform-colors` ESLint rule now permits an optional trailing `{fallback: <literal>}` options object so `PlatformColor('token', {fallback: '#RRGGBB'})` is lint-clean, while still requiring every other argument to be a literal. The options object must have exactly one `fallback` property whose value is a literal, so it stays statically analyzable.
- A new "Lazy Fallback Colors" section in the RNTester `PlatformColor` example demonstrates valid tokens, misses with no fallback (transparent), and misses with hex / `rgb()` / `rgba()` / `#RRGGBBAA` fallbacks across `backgroundColor`, text `color`, and `borderColor`.

Changelog:
[Internal] - PlatformColor: ESLint support and RNTester example for the lazy raw-color fallback

Reviewed By: christophpurrer

Differential Revision: D113329138

fbshipit-source-id: 7d38a8d55b54615d1b131591e99d13e6299eb5cb
meta-codesync Bot pushed a commit to react/react-native that referenced this pull request Aug 6, 2026
Summary:
Pull Request resolved: #57708

An implementation for the RFC in react-native-community/discussions-and-proposals#1008

Adds unit and integration coverage for the PlatformColor raw-color fallback introduced in the parent diff:
- CSSColorTest.cpp: additional CSS `<color>` parse cases pinning the shared parser used on the native fallback path
- PlatformColorFallback-itest.js: JS integration test for token-miss -> fallback

Changelog: [Internal]

Reviewed By: christophpurrer

Differential Revision: D111917092

fbshipit-source-id: 412387d0d598b5556cf7a3eafbc0da60ceaf2725
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