Skip to content

fix(ui): stop setting cursor: 'pointer' on sidebar rows - #956

Merged
dannyhw merged 2 commits into
storybookjs:nextfrom
officialasishkumar:fix/ipad-pointer-cursor-crash
Nov 8, 2026
Merged

dannyhw merged 2 commits into
storybookjs:nextfrom
officialasishkumar:fix/ipad-pointer-cursor-crash

Conversation

@officialasishkumar

Copy link
Copy Markdown
Contributor

Issue: #936

What I did

On iPadOS with a mouse or trackpad, collapsing a sidebar group in a debug build terminates the app with Attempt to unmount a view which has a different index.

React Native turns cursor: 'pointer' into a UIHoverStyle with UIHoverAutomaticEffect on iOS 17+. When the pointer hovers that view, UIKit adds a _UIPointerEffectPlatterView to the same container, and Fabric, which unmounts children by index into subviews, then hits RCTAssert (react/react-native#55489, fix still open in react/react-native#58686). Release builds skip the assertion, but Storybook runs in debug builds, so anyone using an iPad with a pointer hits it.

Changes:

  • Removed cursor: 'pointer' from the tree rows (BranchNode, LeafNode), the root CollapseButton, the search ClearIcon and the search ResultRow in both @storybook/react-native-ui and @storybook/react-native-ui-lite. All of them are TouchableOpacity, which react-native-web already renders with cursor: pointer (its actionable style), so web looks the same. On Android the style was ignored. The only effect on iOS is that the rows no longer get the iPad hover effect that triggers the crash.
  • Added a no-restricted-syntax rule for packages/*/src that flags cursor: 'pointer' and explains why, so it doesn't creep back in while the React Native bug is open. The col-resize / row-resize cursors in the lite ResizeHandle aren't affected, because iOS only maps auto and pointer.
  • Changeset: patch for @storybook/react-native-ui and @storybook/react-native-ui-lite.

I went with removing the style rather than gating it with Platform.OS because on web it does nothing beyond what TouchableOpacity already does.

How to test

pnpm build
pnpm lint

pnpm lint passes. If you put any of the removed cursor: 'pointer' lines back, it fails with the new rule.

Manually, with the reproduction from the issue (https://github.com/ekrapfl/sb-rn-ipad-collapse-crash) or examples/expo-example, use a debug build on an iPad wide enough for the desktop sidebar (e.g. iPad Pro 13" simulator), hover a group row with the pointer for a second, then click it to collapse. It used to crash and now collapses normally. On web (pnpm --filter expo-example web), sidebar rows and search results still show the pointer cursor.

  • Does this need a new example in examples/expo-example? No
  • Does this need an update to the documentation? No

Fixes #936

On iPadOS with a mouse or trackpad, collapsing a sidebar group in a
debug build aborts the app with "Attempt to unmount a view which has a
different index".

React Native maps `cursor: 'pointer'` on iOS 17+ to a UIHoverStyle with
UIHoverAutomaticEffect. When the pointer hovers such a view, UIKit
inserts a `_UIPointerEffectPlatterView` into the same container. Fabric
unmounts children by index into the container's subviews, so once that
extra view is there the indices are off and RCTAssert fails
(react/react-native#55489). Release builds compile the assertion out,
but Storybook runs in debug builds, so every iPad user with a pointer
attached hits it.

The tree rows, the collapse buttons, the search clear button and the
search result rows of both @storybook/react-native-ui and
@storybook/react-native-ui-lite set `cursor: 'pointer'`. All of them are
TouchableOpacity, which react-native-web already renders with a pointer
cursor, so the style did nothing on web and only opted the rows into the
iPad hover effect. Remove it.

Add a `no-restricted-syntax` lint rule for the packages' sources so the
style can't be reintroduced while the React Native bug is unfixed.

Fixes storybookjs#936
@changeset-bot

changeset-bot Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 70d9752

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 9 packages
Name Type
@storybook/react-native-ui Patch
@storybook/react-native-ui-lite Patch
@storybook/addon-ondevice-controls Patch
@storybook/react-native Patch
@storybook/addon-ondevice-actions Patch
@storybook/addon-ondevice-backgrounds Patch
@storybook/addon-ondevice-notes Patch
@storybook/react-native-theming Patch
@storybook/react-native-ui-common Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 2, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-02T15:16:16.420934Z 339ec78 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

# Conflicts:
#	packages/react-native-ui-lite/src/TreeNode.tsx
#	packages/react-native-ui/src/TreeNode.tsx
@dannyhw
dannyhw merged commit cbeb0c2 into storybookjs:next Nov 8, 2026
1 check passed
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.

iPad: app crashes when collapsing a sidebar group (cursor: 'pointer' + UIHoverStyle)

2 participants