Skip to content

fix(iOS, Stack v4+): reapply header config once the navigation bar has a window - #4588

Open
LizunovSergey wants to merge 1 commit into
software-mansion:mainfrom
LizunovSergey:fix/4479-prominent-header-button-off-window
Open

fix(iOS, Stack v4+): reapply header config once the navigation bar has a window#4588
LizunovSergey wants to merge 1 commit into
software-mansion:mainfrom
LizunovSergey:fix/4479-prominent-header-button-off-window

Conversation

@LizunovSergey

Copy link
Copy Markdown

Description

Closes #4479.

A UIBarButtonItem assigned to a navigation bar that is not part of any window misses the styling UIKit resolves against that window. On iOS 26 a variant: 'prominent' item then renders as a bare glyph — no background — until the items are assigned again.

A stack nested in tabs reaches that state on every tab re-selection that follows its view being detached, which is what Appearance.setColorScheme() on another tab triggers. -[RNSScreenStackView navigationController:willShowViewController:animated:] applies the header config while the bar is still window-less, and nothing reassigns the items afterwards, so the button stays background-less for the whole visit. Switching tabs once more assigns the items again, this time into an attached bar, which is why the button "repairs itself" on the second visit.

Instrumented RNSScreenStackHeaderConfig to confirm this. RNS does identical work in the broken and the self-repairing pass — same view controller, one willShowViewController:, a fresh RNSBarButtonItem with variant=prominent resolved to UIBarButtonItemStyleProminent — and the only difference is the bar's window:

# tab re-selection right after Appearance.setColorScheme() on the other tab
applied vc=0x13b023700 barWindow=0x0                <- button renders without background
# any later tab switch
applied vc=0x13b023700 barWindow=0x1061c0400        <- button renders correctly

Reusing the previous UIBarButtonItem instances instead of building new ones does not help, so this is not item churn — it is the window the bar is missing when the items land on it.

Changes

  • RNSScreenStackHeaderConfig records when an application landed on a window-less navigation bar, and exposes -updateViewControllerIfAppliedOutsideWindow to repeat exactly that application.
  • RNSScreenStackView -didMoveToWindow asks the top screen's header config to repeat it once the stack is in a window.
  • The repeat is dispatched one main-queue turn later. The hierarchy insertion that brought the bar into the window is still in progress while didMoveToWindow runs, and applying synchronously there leaves the styling unrealized exactly as before — verified on device before settling on the async hop.
  • Added Test4479 to the issue tests, based on the MRE @t0maboro attached to the issue.

Two notes on scope:

  • The flag is not gated on iOS version. The incomplete application is a general property of applying header config to a detached bar; only the visible symptom found so far is iOS 26 specific.
  • If a bar were to lack a window while the stack view already had one, no didMoveToWindow follows and the flag simply stays set until the next attach — the same behaviour as today, no regression.

Before & after - visual documentation

Test4479 on iPhone 17 Pro, iOS 26.5, after: tab One → tab Two → toggle appearance → back to tab One.

Before After

Test plan

apps/src/tests/issue-tests/Test4479.tsx (new), run through FabricExample on an iPhone 17 Pro / iOS 26.5 simulator.

  1. Issue Tests → Test4479. Tab One shows a prominent + in the header.
  2. Switch to tab Two, press Toggle appearance, then go back to One.
  3. Switch back to tab One.

Before the change the + has lost its background and keeps it lost for the whole visit; after the change it keeps the background. Repeated toggles and tab switches were also checked in both directions.

Regression checks on the same build:

  • Playgrounds → Bar Button ItemsProminent Style Button: a prominent item in a plain (non-tabbed) stack still renders with its background.
  • Repeated tab switches without an appearance change behave as before, no flicker from the extra application.
  • yarn check-types passes; the touched Objective-C files are unchanged under the repository .clang-format, and the new test file is Prettier-clean.

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

Written by an agent (Claude Code, claude-opus-5) on behalf of @LizunovSergey; the diagnosis above was verified on a simulator rather than inferred.

…s a window

A bar button item assigned to a navigation bar that is not part of any window
misses the styling UIKit resolves against that window. On iOS 26 a `prominent`
item then renders without its background until the items are assigned again.

A stack nested in tabs hits this on every tab re-selection that follows its
view being detached: `willShowViewController:` applies the config while the bar
is still window-less, and nothing reassigns the items afterwards, so the button
stays background-less for the whole visit.

The config now records an application that landed on a window-less bar, and
`RNSScreenStackView` asks it to repeat that application when the stack enters a
window. The repeat is dispatched one main queue turn later, because the
hierarchy insertion that brought the bar into the window is still in progress
when `didMoveToWindow` runs, and applying synchronously leaves the styling
unrealized exactly as before.
@coderabbitai

coderabbitai Bot commented Sep 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Team

Run ID: 9a5cc643-a545-480a-8eb8-9a9588c5577e

📥 Commits

Reviewing files that changed from the base of the PR and between 2cc07a9 and 3dc728b.

📒 Files selected for processing (5)
  • apps/src/tests/issue-tests/Test4479.tsx
  • apps/src/tests/issue-tests/index.ts
  • ios/legacy/RNSScreenStack.mm
  • ios/legacy/RNSScreenStackHeaderConfig.h
  • ios/legacy/RNSScreenStackHeaderConfig.mm

Included review availability: Your plan provides up to 8 included reviews per hour; 7 remain after this review.


📝 Walkthrough

Walkthrough

The iOS stack now reapplies header configuration after a navigation bar attaches to a window. A new issue test reproduces the prominent toolbar button scenario across tabs and appearance changes.

Changes

Prominent header styling restoration

Layer / File(s) Summary
Track and reapply out-of-window header configuration
ios/legacy/RNSScreenStackHeaderConfig.h, ios/legacy/RNSScreenStackHeaderConfig.mm
RNSScreenStackHeaderConfig tracks applications made outside a window and asynchronously reapplies the configuration when valid view-controller and parent references exist.
Trigger restoration and expose the issue reproduction
ios/legacy/RNSScreenStack.mm, apps/src/tests/issue-tests/Test4479.tsx, apps/src/tests/issue-tests/index.ts
RNSScreenStack triggers the retry after window attachment. Test4479 adds the two-tab appearance-change reproduction and exports it through the issue-test index.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to 3dc72

This localized iOS fix reapplies existing header styling when the navigation bar becomes attached, preventing prominent buttons from losing their background during tab switches. No actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant TabTwo
  participant Appearance
  participant RNSScreenStack
  participant RNSScreenStackHeaderConfig
  participant UINavigationBar
  TabTwo->>Appearance: Toggle color scheme
  Appearance->>RNSScreenStack: Update tab appearance
  RNSScreenStack->>RNSScreenStackHeaderConfig: Apply header configuration
  RNSScreenStackHeaderConfig->>UINavigationBar: Detect bar outside a window
  RNSScreenStack->>RNSScreenStackHeaderConfig: Retry after window attachment
  RNSScreenStackHeaderConfig->>UINavigationBar: Reapply prominent button styling
Loading

Suggested reviewers: kmichalikk

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. (2 skipped: 2 … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the primary iOS fix: reapplying the header configuration after the navigation bar enters a window.
Description check ✅ Passed The description explains the iOS header-button styling issue, the root cause, the implementation, the regression test, and the validation performed.
Linked Issues check ✅ Passed The changes satisfy issue #4479 by tracking header configuration applied to a window-less navigation bar, asynchronously reapplying it after attachment, and adding a regression test for the prominent …
Out of Scope Changes check ✅ Passed The changes are within scope for issue #4479. They include the native iOS fix, the required declaration, and a focused regression test with its index export.
Full details: Linked Issues check

Explanation

The changes satisfy issue #4479 by tracking header configuration applied to a window-less navigation bar, asynchronously reapplying it after attachment, and adding a regression test for the prominent toolbar button.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files. (2 skipped: 2 unsupported.)

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Warning

⚠️ This pull request shows signs of AI-generated slop (trivial_assertion). It has been flagged by CodeRabbit slop detection and should be reviewed carefully.

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.

[iOS 26] variant="prominent" header button loses its background after Appearance.setColorScheme on an unselected tab

1 participant