Skip to content

Bottom accessory content view opacity glitch: invalidateLayer resets visibility #3798

@fedeciancaglini

Description

@fedeciancaglini

Description

The bottom accessory content view visibility switching (for RN >= 0.82, dual-content-view approach) can glitch, showing the wrong content view (e.g., the inline copy when the tab bar is in regular/expanded state). This makes UI elements that are conditionally rendered per-placement inaccessible.

RCTViewComponentView.invalidateLayer unconditionally resets self.layer.opacity to the React props value (typically 1.0). This overwrites the 0.0 opacity that RNSTabsBottomAccessoryHelper sets to hide the inactive content view.

The existing mitigations call handleContentViewVisibilityForEnvironmentIfNeeded after:

  1. finalizeUpdates: (original fix)
  2. traitCollectionDidChange: (fix in fix(iOS, Tabs): bottom accessory opacity on appearance change #3467)

However, invalidateLayer can be triggered from other code paths not covered by these two (mount/unmount cycles of the accessory, prop changes on parent views, animated transitions). When this happens, opacity is reset to 1.0 on both content views, leaving both copies visible simultaneously.

Proposed fix: Override invalidateLayer directly on RNSTabsBottomAccessoryContentComponentView:

- (void)invalidateLayer
{
  [super invalidateLayer];
  [_accessoryView.helper handleContentViewVisibilityForEnvironmentIfNeeded];
}

Steps to reproduce

  1. Use NativeTabs.BottomAccessory with different content for regular vs inline placement (e.g., extra buttons only in regular mode)
  2. Set minimizeBehavior="onScrollDown" on NativeTabs
  3. Scroll down on a tab with native scroll to collapse the tab bar (accessory goes inline)
  4. Switch to a tab where the scroll view does not reach the native tab bar (tab bar expands back)
  5. The inline content view persists while the tab bar is in expanded/regular state

The glitch is intermittent and more likely when the accessory mount coincides with other prop changes on NativeTabs.

Snack or a link to a repository

We do not have a minimal reproduction repo yet. The issue occurs in a production app with NativeTabs bottom accessory. The root cause is clear from reading the native source: RCTViewComponentView.invalidateLayer resets layer.opacity and only two of many possible call sites are mitigated.

Screens version

4.24.0

React Native version

0.83.2

Platforms

  • iOS

JavaScript runtime

Hermes

Workflow

Expo managed workflow

Architecture

Fabric (New Architecture)

Build type

Debug mode

Device

Real device

Device model

iPhone 16 Pro (iOS 26.0 beta)

Acknowledgements

Yes

Metadata

Metadata

Assignees

Labels

missing-reproThis issue need minimum repro scenarioplatform:iosIssue related to iOS part of the library

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions