Skip to content

feat(iOS, Stack v5): Add menuRepresentation prop to header items - #4587

Open
kmichalikk wants to merge 2 commits into
mainfrom
@kmichalikk/stack-v5-custom-menu-representation
Open

feat(iOS, Stack v5): Add menuRepresentation prop to header items#4587
kmichalikk wants to merge 2 commits into
mainfrom
@kmichalikk/stack-v5-custom-menu-representation

Conversation

@kmichalikk

@kmichalikk kmichalikk commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Closes https://github.com/software-mansion/react-native-screens-labs/issues/1179

Description

This PR adds menuRepresentation prop to leading and trailing header items. This allows for specifying different menu definition for when the item is moved to the overflow menu.

Without this prop:

  • for regular items, UIKit takes the menu (if specified) and onPress action (if specified) and combines them. This may break UI if, for instance, the menu consists only of radio buttons - the onPress action would be added nonetheless
  • custom items are not present at all. What's more, if the header has only custom items, the overflow menu button will render but won't show anything on press

Important

The feature is testable on iOS 26+. Below this version, items never go into overflow menu, unless the overflow menu is already present, or other conditions are met (interface style + specific item groups setup - not supported in foreseeable future)

Changes

  • added menuRepresentation prop and wired it the same as menu

Before & after - visual documentation

menu-representation.mov

Test plan

Use Stack Header Menu (iOS) SFT

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

@kmichalikk
kmichalikk requested a review from t0maboro September 2, 2026 15:35
@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: 17b8789d-e6cd-4bae-baca-2d165df186c1

📥 Commits

Reviewing files that changed from the base of the PR and between 3703115 and 075dc68.

📒 Files selected for processing (1)
  • apps/src/tests/single-feature-tests/stack-v5/test-stack-header-menu-ios/scenario.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/src/tests/single-feature-tests/stack-v5/test-stack-header-menu-ios/scenario.md

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


📝 Walkthrough

Walkthrough

The change adds an optional menuRepresentation to iOS stack header items. JavaScript forwards it to native code, and native coordinators apply and reapply it on supported iOS versions. The iOS test scenario adds configuration and manual coverage for overflow-menu representations.

Changes

iOS menu representation

Layer / File(s) Summary
Header contract and prop wiring
src/components/stack/header/..., src/fabric/stack/StackHeaderItemIOSNativeComponent.ts
JavaScript types and native props accept menuRepresentation. Header items resolve its icons before forwarding it to the native component.
Native menu representation state
ios/stack/header/RNSStackHeaderItemComponentView.*
The component view stores, resets, maps, and invalidates menu representation data.
Bar button application and reapplication
ios/stack/header/RNSStackHeaderMenuCoordinator.*, ios/stack/screen/RNSStackScreenHeaderCoordinator.mm
The coordinators apply or clear menu representations on iOS 16 and later, and reapply them after invalidation.
Scenario configuration and coverage
apps/src/tests/single-feature-tests/stack-v5/test-stack-header-menu-ios/*
The scenario adds radio menu representations, a configuration toggle, and manual overflow-menu steps. Coverage is marked partial because the new section is not covered by E2E tests.

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

Merge Risk: ⚪ Minimal · up to 075dc

The change adds iOS header menu representation support and associated scenario coverage. No concrete unresolved merge-readiness risk is identified.

Sequence Diagram(s)

sequenceDiagram
  participant HeaderConfig
  participant StackHeaderItem
  participant NativeComponent
  participant HeaderCoordinator
  participant UIBarButtonItem
  HeaderConfig->>StackHeaderItem: pass menuRepresentation
  StackHeaderItem->>NativeComponent: pass resolved menuRepresentation
  NativeComponent->>HeaderCoordinator: update header item
  HeaderCoordinator->>UIBarButtonItem: apply menuRepresentation
  UIBarButtonItem-->>HeaderCoordinator: invalidate menu representation
  HeaderCoordinator->>UIBarButtonItem: reapply menuRepresentation
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 10 files. (1 skipped: … Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely identifies the main change: adding the iOS Stack v5 header-item menuRepresentation prop.
Description check ✅ Passed The description directly explains the new menuRepresentation prop, its purpose, implementation scope, testing plan, and iOS version constraints.
Full details: Docstring Coverage

Explanation

Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 6 functions across 10 files. (1 skipped: 1 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.

@kmichalikk kmichalikk self-assigned this Sep 3, 2026

@t0maboro t0maboro left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The code looks good, but on iOS 18, items don't land in an overflow menu. Is that intentional in this example?

Image

@kmichalikk

Copy link
Copy Markdown
Contributor Author

This is native iOS 18. Before 26 the overflow menu existed but the conditions were stricter and we don't meet them (interface style, item groups). We will have additionalOverflowItems exposed so the workaround will probably be to prepopulate overflow menu with something. As a quick test I hardcoded one item in the menu on the native side and it looks like this:

image

@kmichalikk
kmichalikk requested a review from t0maboro September 3, 2026 09:52

@LKuchno LKuchno left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I've left a few comments with minor corrections.

## E2E test

Full: Covers all manual scenario steps.
Partial: Covers all manual scenario steps except the **Menu representation** section.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please keep wording agreed for E2E test/coverage in RFC-1076 -> Full/Incomplete/TBD

Suggested change
Partial: Covers all manual scenario steps except the **Menu representation** section.
Incomplete: Covers all manual scenario steps except the **Menu representation** section.

Comment on lines +20 to +21
- Menu representation section requires iOS >= 16
- On iOS 18, items don't go into overflow by default, UIKit attempts to pack them all into header, test `menuRepresentation` on iOS 26+

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If on second bullet we say that menuRepresentation should be tested on iOS26+, does first point make sense here?


## Prerequisites

- iOS / iPadOS emulator

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I know it was not changed in this PR but we can unify it with most of iOS scenarios.
Also I removed iPadOS from list as there are only steps for iPhone in this scenario.

Suggested change
- iOS simulator or device

6. Click Repr 1 Radio 2
- [ ] A toast "Repr 1 selected "repr-radio-1-2"" is displayed
- [ ] When reopened, Repr 1 Radio 2 is checked and Radio 1 is not
7. Open Repr 2

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There is no Repr 2

Image
Suggested change
7. Open Repr 2
7. Open Repr 0

- [ ] Two items moved to overflow menu
4. Open the overflow menu
- [ ] Overflowed items appear as **Repr #** submenus
- [ ] Custom items are represented in the same way

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not really sure what I should see and check here?

- [ ] A toast "Repr 1 selected "repr-radio-1-2"" is displayed
- [ ] When reopened, Repr 1 Radio 2 is checked and Radio 1 is not
7. Open Repr 2
- [ ] It contains three radio items, Repr 2 Radio 1 is selected by default

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Here also it should be corrected

Suggested change
- [ ] It contains three radio items, Repr 2 Radio 1 is selected by default
- [ ] It contains three radio items, Repr 0 Radio 1 is selected by default

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.

3 participants