Skip to main content
Get Storybook for React Native running in your project with a single command.
Make sure you align your storybook dependencies to the same major version or you will see broken behaviour.

Prerequisites

  • Node.js 20 or higher
  • An existing React Native or Expo project
  • For Expo: Expo SDK 49 or higher
  • For React Native CLI: React Native 0.72 or higher

Installation

1

Run the initialization command

Use the Storybook CLI to automatically set up Storybook in your project:
npm create storybook@latest
The CLI will:
  • Detect your project type (Expo or React Native CLI)
  • Install required dependencies
  • Create a .rnstorybook configuration folder
  • Set up example stories
2

Update your Metro configuration

Wrap your Metro config with the withStorybook function:
Create or update metro.config.js:
metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const { withStorybook } = require('@storybook/react-native/metro/withStorybook');

const config = getDefaultConfig(__dirname);

module.exports = withStorybook(config);
3

Set up Reanimated

Add the Reanimated plugin to your Babel config:
babel.config.js
module.exports = {
  presets: ['module:@react-native/babel-preset'],
  plugins: [
    // ... your other plugins
    'react-native-reanimated/plugin', // Must be last
  ],
};
The Reanimated plugin must be the last plugin in your Babel config.
4

Render Storybook in your app

Return Storybook’s UI in your app entry point:
The simplest approach - export Storybook directly:
App.tsx
export { default } from './.rnstorybook';
5

Start your app

npx expo start
You should now see Storybook’s UI when you open your app!

Your first story

The CLI creates example stories for you. Let’s create a simple Button component story:

Create a component

components/Button.tsx
import React from 'react';
import { Pressable, Text, StyleSheet } from 'react-native';

interface ButtonProps {
  text: string;
  onPress?: () => void;
  color?: string;
}

export const Button = ({ text, onPress, color = '#007AFF' }: ButtonProps) => {
  return (
    <Pressable
      style={[styles.button, { backgroundColor: color }]}
      onPress={onPress}
    >
      <Text style={styles.text}>{text}</Text>
    </Pressable>
  );
};

const styles = StyleSheet.create({
  button: {
    paddingHorizontal: 20,
    paddingVertical: 10,
    borderRadius: 8,
  },
  text: {
    color: 'white',
    fontSize: 16,
    fontWeight: '600',
  },
});

Write a story

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

const meta = {
  component: Button,
} satisfies Meta<typeof Button>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Basic: Story = {
  args: {
    text: 'Hello World',
    color: '#007AFF',
  },
};

export const Purple: Story = {
  args: {
    text: 'Purple Button',
    color: '#8B5CF6',
  },
};

export const Large: Story = {
  args: {
    text: 'Large Button',
    color: '#10B981',
  },
};

Configure story paths

Update .rnstorybook/main.ts to tell Storybook where to find your stories:
.rnstorybook/main.ts
import type { StorybookConfig } from '@storybook/react-native';

const main: StorybookConfig = {
  stories: ['../components/**/*.stories.?(ts|tsx|js|jsx)'],
  addons: [
    '@storybook/addon-ondevice-controls',
    '@storybook/addon-ondevice-actions',
  ],
};

export default main;
Use glob patterns to match all your story files. Common patterns:
  • ../components/**/*.stories.tsx - All stories in components directory
  • ../**/*.stories.tsx - All stories in the project
  • ../src/**/*.stories.@(ts|tsx|js|jsx) - Multiple extensions

Add interactivity with addons

Install on-device addons to add interactive controls:
npm install --save-dev @storybook/addon-ondevice-controls @storybook/addon-ondevice-actions
Register them in your .rnstorybook/main.ts:
.rnstorybook/main.ts
import type { StorybookConfig } from '@storybook/react-native';

const main: StorybookConfig = {
  stories: ['../components/**/*.stories.?(ts|tsx|js|jsx)'],
  addons: [
    '@storybook/addon-ondevice-controls',
    '@storybook/addon-ondevice-actions',
  ],
};

export default main;
Now you can adjust your Button’s props directly in the Storybook UI!

Troubleshooting

If you see Metro errors about require.context, make sure you’ve wrapped your Metro config with withStorybook() and restarted the Metro bundler.
Ensure react-native-reanimated/plugin is the last plugin in your babel.config.js and restart your app with cache cleared: npx expo start --clear or npm start -- --reset-cache.
Add the Storybook types to your tsconfig.json:
tsconfig.json
{
  "compilerOptions": {
    "types": ["@storybook/react-native/types"]
  }
}
Make sure your story file paths in .rnstorybook/main.ts match your actual file locations. Run the generate command to regenerate the story index: npx sb-rn-get-stories.

Next steps

Writing stories

Learn the Component Story Format syntax

Addons

Explore available on-device addons

Configuration

Configure Metro and Storybook options

Testing

Use stories in your unit tests

Build docs developers (and LLMs) love