Skip to content

fix(android) transparent header backgroundColor dropped by Props 2.0 - #4524

Open
delekta wants to merge 1 commit into
software-mansion:4.27-stablefrom
delekta:fix/header-transparent-props-2-0
Open

fix(android) transparent header backgroundColor dropped by Props 2.0#4524
delekta wants to merge 1 commit into
software-mansion:4.27-stablefrom
delekta:fix/header-transparent-props-2-0

Conversation

@delekta

@delekta delekta commented Aug 19, 2026

Copy link
Copy Markdown

Description

On Android Fabric with Props 2.0 (enablePropsUpdateReconciliationAndroid), ScreenStackHeaderConfig backgroundColor="transparent" never reaches native. JS still has the color (processColor is 0). Native never calls setBackgroundColor, so the toolbar keeps Material colorPrimary.

iOS is unaffected (it does not use the getDiffProps path).

Android HostPlatformColor::UndefinedColor is 0, and so is processColor('transparent') / '#00000000' / 'rgba(0,0,0,0)'. Without generateOptionalProperties, codegen emits SharedColor backgroundColor{} whose default is also 0. On CREATE, Props 2.0 diffs against that default, omits the key, and Kotlin never paints.

This is a CREATE-path bug. A red → transparent UPDATE diffs against the previous color and can hide it.

Minimal repro: https://github.com/delekta/screens-transparent-header-bug-repro
RN 0.87.0, screens 4.27.0, screens-only (no React Navigation required).

Do not disable Props 2.0 as the library fix.

Changes

  • Set generateOptionalProperties: true on RNSScreenStackHeaderConfig so omitted is nullopt and transparent is optional(0). The diff then emits 0 and native setBackgroundColor(0) runs.
  • The flag is component-wide (optional strings, colors, mixed arrays), so native readers are updated:
    • Android C++: title.empty()!title.has_value() || title->empty() in RNSScreenShadowNode.cpp
    • iOS Fabric updateProps: unwrap std::optional for RCTNSStringFromStringNilIfEmpty, RCTUIColorFromSharedColor, and header bar-button vectors
  • Kotlin ViewManagers are unchanged (Int? already). Unset color still skips the setter (theme bar). Transparent now applies 0.

Please also cherry-pick onto main (5.0 / src/fabric/legacy/…) if that spec is still used there.

Before & after - visual documentation

Chip 2. transparent on the repro (CREATE / remount). Expected: lime page shows through the header. Fail: leftover Material bar.

Before After
transparent-header-before.mov
transparent-header-after.mov

Opaque red (chip 1) should stay red in both.

Test plan

Repro: https://github.com/delekta/screens-transparent-header-bug-repro

npm install
npm start
npm run android

Keep ENABLE_PROPS_2_0 = true in MainApplication.kt. Each chip remounts the stack so 2–4 are CREATE.

  • Chip 1. Red — header and page both red (control).
  • Chip 2. transparent — lime page; header must look lime (see-through). Fail = leftover Material bar.
  • Chips 3 / 4#00000000 and rgba(0,0,0,0) same as transparent.
  • Chip 5#FFFFFF00 still works (alpha 0, RGB ≠ 0).
  • Chip 6 — dark, then UPDATE to transparent still works.
  • Control: set ENABLE_PROPS_2_0 = false, rebuild; chip 2 already correct without this PR.
  • iOS: header title, colors, and bar button items unchanged.

Same bug via native-stack: in the repro index.js import ./App.native-stack instead of ./App.

No new example files in this repo; the repro app is the test.

Checklist

  • Included code example that can be used to test this change.
  • For visual changes, included screenshots / GIFs / recordings documenting the change.
  • For API changes, updated relevant public types.
  • Ensured that CI passes

@t0maboro
t0maboro self-requested a review August 19, 2026 14:14
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