Skip to content

πŸ› Storybook Bottom Sheet Menu Not Opening When Stories Use React Native ReanimatedΒ #802

@rakeshsinha01

Description

@rakeshsinha01

Describe the bug
Storybook's bottom sheet menu becomes completely non-functional when displaying stories that contain components using React Native Reanimated. The menu icon appears at the bottom of the screen but is unresponsive - tapping it does nothing and the bottom sheet panel fails to open. This prevents access to controls, actions, and all other on-device addons.

Importantly, this issue only occurs when viewing stories with Reanimated-based components. Stories with plain React Native components work perfectly, and the bottom sheet menu functions normally.

To Reproduce
Steps to reproduce the behavior:

  1. Create a React Native component that uses Reanimated APIs (useAnimatedStyle, useSharedValue, withTiming, etc.)
  2. Create a Storybook story for this component
  3. Launch Storybook in your React Native app
  4. Navigate to the story containing the Reanimated component
  5. Look at the bottom of the screen - the menu icon is visible
  6. Tap the menu icon to open the addons/controls panel
  7. Observe: Nothing happens - the bottom sheet doesn't slide up and remains unresponsive

Expected behavior
When tapping the bottom menu icon, Storybook should:

  • Open a bottom sheet panel sliding up from the bottom of the screen
  • Display the controls addon showing the component's props/argTypes
  • Display the actions addon and other registered on-device addons
  • Allow users to interact with story controls to test different component states

This behavior works correctly for stories that don't use Reanimated, but fails for stories with Reanimated components.

Screenshots
N/A - The issue is functional (touch interaction) rather than visual. The UI appears correct but the interaction is broken.

Storybook-Reanimated-Issue.mov

Code snippets

Component with Reanimated (triggers the bug)

// components/Button/Button.tsx
import React, { useEffect } from 'react';
import Animated, { 
  useAnimatedStyle, 
  useSharedValue, 
  withRepeat, 
  withTiming,
  cancelAnimation,
  Easing
} from 'react-native-reanimated';
import { Pressable, Text } from 'react-native';
import { Icon } from "../Icon/Icon";

interface ButtonProps {
  isLoading?: boolean;
}

export const Button: React.FC<ButtonProps> = ({ isLoading = false }) => {
  const rotation = useSharedValue(0);

  useEffect(() => {
    if (isLoading) {
      rotation.value = withRepeat(
        withTiming(360, { duration: 1000, easing: Easing.linear }),
        -1
      );
    } else {
      cancelAnimation(rotation);
      rotation.value = 0;
    }
  }, [isLoading]);

  const animatedLoaderStyle = useAnimatedStyle(() => ({
    transform: [{ rotate: `${rotation.value}deg` }],
  }));

  return (
    <Pressable>
      {isLoading && (
        <Animated.View style={animatedLoaderStyle}>
          <Icon icon={faSpinner} />
        </Animated.View>
      )}
      <Text>Button</Text>
    </Pressable>
  );
};

Story Configuration

// components/Button/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react-native';
import { Button } from './Button';

const meta = {
  title: 'Components/Button',
  component: Button,
  argTypes: {
    isLoading: { control: 'boolean' },
  },
} satisfies Meta<typeof Button>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Loading: Story = {
  args: {
    isLoading: true,
  },
};

export const Default: Story = {
  args: {
    isLoading: false,
  },
};

babel.config.js

module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    'react-native-reanimated/plugin',
  ],
};

package.json (dependencies)

{
  "dependencies": {
    "react": "18.3.1",
    "react-native": "0.75.4",
    "react-native-reanimated": "3.16.7",
    "react-native-gesture-handler": "2.20.0",
    "react-native-svg": "^15.10.1",
    "styled-components": "^6.1.0"
  },
 "devDependencies": {
    "@babel/core": "^7.20.0",
    "@babel/preset-env": "^7.20.0",
    "@babel/runtime": "^7.20.0",
    "@gorhom/bottom-sheet": "^5.2.3",
    "@react-native-async-storage/async-storage": "^2.2.0",
    "@react-native-community/cli": "^14.0.0",
    "@react-native-community/cli-platform-android": "^14.0.0",
    "@react-native-community/cli-platform-ios": "^14.0.0",
    "@react-native-community/datetimepicker": "^8.4.4",
    "@react-native-community/slider": "^4.5.7",
    "@react-native/babel-preset": "0.75.4",
    "@react-native/eslint-config": "0.75.4",
    "@react-native/gradle-plugin": "0.75.4",
    "@react-native/metro-config": "0.75.4",
    "@react-native/typescript-config": "0.75.4",
    "@storybook/addon-ondevice-actions": "^9.1.4",
    "@storybook/addon-ondevice-controls": "^9.1.4",
    "@storybook/react-native": "^9.1.4",
    "@types/react": "^18.2.6",
    "@types/react-test-renderer": "^18.0.0",
    "babel-jest": "^29.6.3",
    "babel-loader": "^8.4.1",
    "eslint": "^8.19.0",
    "jest": "^29.6.3",
    "prettier": "2.8.8",
    "react-dom": "18.3.1",
    "react-native-gesture-handler": "^2.28.0",
    "react-native-safe-area-context": "^5.6.0",
    "react-test-renderer": "18.3.1",
    "storybook": "^9.1.4",
    "typescript": "5.0.4"
  },
}

System:

Environment Info:

  Storybook: 9.1.4
  React Native: 0.75.4
  React Native Reanimated: 3.16.7
  React Native Gesture Handler: 2.20.0
  
  Addons:
    @storybook/addon-ondevice-controls: 9.1.4
    @storybook/addon-ondevice-actions: 9.1.4
  
  Platform: iOS/Android
  Package Manager: pnpm
  Project Type: Monorepo

Additional context

Key Observations

  1. Works with non-Reanimated components: The bottom sheet menu functions perfectly when viewing stories that don't use Reanimated
  2. Breaks only with Reanimated components: The issue occurs exclusively when displaying stories containing components that use Reanimated APIs
  3. Component renders correctly: The Reanimated component itself displays and animates properly in the story
  4. Menu icon is visible: The UI element appears at the bottom but has zero touch interaction
  5. No console errors: In most cases, there are no error messages indicating the problem

Since React Native Reanimated is the recommended and most widely used animation library for React Native, this severely limits Storybook's utility for contemporary React Native development.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions