Before getting into the guide consider using a template for a simpler setup process.
Prebuilt Templates:
For expo you can use this template with the following command
npx create-expo-app --template expo-template-storybook AwesomeStorybookFor react native cli you can use this template
npx @react-native-community/cli init MyApp --template react-native-template-storybookYou may wish to setup everything yourself, you can use the following guide to do so.
Expo
expo install @storybook/react-native @react-native-async-storage/async-storage react-dom react-native-safe-area-context react-native-reanimated react-native-gesture-handler @gorhom/bottom-sheet react-native-svgReact native CLI
yarn add -D @storybook/react-native @react-native-async-storage/async-storage react-native-safe-area-context react-dom react-native-reanimated react-native-gesture-handler @gorhom/bottom-sheet react-native-svgIOS
If running on an IOS device with rn cli make sure to run pod install first
cd ios; pod install; cd ..;Create a folder called .rnstorybook with files: main.ts, preview.tsx, index.tsx
You can use this one-liner to quickly create those files:
mkdir .rnstorybook && touch .rnstorybook/main.ts .rnstorybook/preview.tsx .rnstorybook/index.tsximport type { StorybookConfig } from '@storybook/react-native';
const main: StorybookConfig = {
stories: ['../components/**/*.stories.?(ts|tsx|js|jsx)'],
addons: [],
};
export default main;import type { Preview } from '@storybook/react-native';
const preview: Preview = {
parameters: {},
decorators: [],
};
export default preview;Add the following to the scripts in your package.json.
{
"scripts": {
"storybook-generate": "sb-rn-get-stories"
}
}run yarn storybook-generate
import { view } from './storybook.requires';
import AsyncStorage from '@react-native-async-storage/async-storage';
const StorybookUIRoot = view.getStorybookUI({
storage: {
getItem: AsyncStorage.getItem,
setItem: AsyncStorage.setItem,
},
});
export default StorybookUIRoot;Update your metro config to enable transformer.unstable_allowRequireContext
Expo
First create metro config file if you don't have it yet.
npx expo customize metro.config.jsThen set transformer.unstable_allowRequireContext to true
const { getDefaultConfig } = require('expo/metro-config');
const { withStorybook } = require('@storybook/react-native/metro/withStorybook');
const defaultConfig = getDefaultConfig(__dirname);
module.exports = withStorybook(defaultConfig);React native
const { getDefaultConfig } = require('@react-native/metro-config');
const { withStorybook } = require('@storybook/react-native/metro/withStorybook');
const defaultConfig = getDefaultConfig(__dirname);
module.exports = withStorybook(defaultConfig);Add a stories file
In the main.ts we created the path was set as ../components/\*_/_.stories.?(ts|tsx|js|jsx) which matches any .stories file inside the components folder.
Create a file called Button.stories.tsx in the components folder.
import type { Meta, StoryObj } from '@storybook/react-native';
import { Button } from 'react-native';
const meta = {
title: 'React Native Button',
component: Button,
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Basic: Story = {
args: {
title: 'Hello world',
},
};This is a simple example you can do more by adding addons and exploring more features of storybook.
The only thing left to do is return Storybook's UI in your app entry point (such as App.tsx) like this:
export { default } from './.rnstorybook';If you want to be able to swap easily between storybook and your app, have a look at this blog post
Then you can run yarn ios or yarn android to run the app like normal.