Storybook is a UI development workshop for components and pages. It's used by many teams for all kinds of reasons. You can develop components in isolation, run visual tests and even validate the accessibility of your UI.
Storybook started off web focused and has expanded to many different platforms since then. One of those platforms is React Native.
Storybook for React Native is a catalog of all your components and states, that runs inside your iOS or Android app, on your mobile device. This is great for seeing your React Native components in their production setting, but also has some disadvantages when compared to Storybook's web UI.
That's why I'm excited to announce Storybook for React Native Web, a new complementary approach to developing and sharing React Native components in Storybook.
I've been working on a new approach of using a storybook with react-native that has all the functionality of storybook on the web. This is acheived by using the react-native-web library to make your components available in the browser. I've done the config for you in this addon and you just need to add it to your project.
In the video below I am interacting with some react native components in the browser. The components displayed use features from popular React Native libraries such as: the animation library react-native-reanimated, and a common library for handling interactions react-native-gesture handler.
rnsb.mp4
React Native has its own Storybook implementation at @storybook/react-native however it has some limitations. The storybook UI is built for the web and so a lot of things need to be re-implemented for react native in order to support the full feature set.
The result of this is that react native storybook supports only a very small portion of the addons that exist for Storybook on the web platform. This also means external tools like visual testing for Storybook need a custom implementation in order to support react native.
This has led to an incomplete experience for react native when compared with the web. Storybook for React Native has its place for displaying components natively on the device, and I personally see a lot of potential with React Native Storybook beyond that. However in order to reach that potential a lot of work is needed, and it's mostly repeated work such as re-implementing features already existing on the web.
The project that I want to show you now should help bridge the gap today for react native. Meaning you can have the full functionality that you know and love from Storybook on the web platform.
Note: work on @storybook/react-native will continue and 6.0 will be coming out. I would love to talk more about my vision for react native storybook 6.x in a future post if there is interest.
In an ideal situation we would have storybook for react native but with support for all popular addons and existing tools used on the web storybook. Is this possible?
Well if you're here you probably guessed that the answer is yes. There are of course some limitations, however I think that for many use cases it will be worth it. The main thing that comes to mind is UI library maintainers that want to show off their react-native components in an interactive way.
You might be surprised at the number of react native libraries that already fully support the web platform. Also if you've been following the react native scene you'll know that facebook is putting a strong emphasis on the many platform vision.
if we look at some of the top downloaded libraries for react native based on npm numbers:
- react-navigation
- react-native-screens
- react-native-gesture-handler
- react-native-svg
- react-native-reanimated
- react-native-vector-icons
All of these libraries have support for the web platform in some way. In fact I've tested many of the popular libraries with this new addon and they all work very well on the web.
This addon provides you with a simple setup for using the reactjs storybook in a react native project. You can run it locally or easily deploy it as a website for others to see. The best part is that since it's running on the web with the ReactJS configuration most addons should work with no changes necessary.
That means:
- Much better UI/UX
- Popular add-ons such as Docs supported out of the box
- Chromatic and other visual testing tools supported
- Easily share with stakeholders such as designers and product owners (publish storybook as a webapp)
- Full support for the latest storybook features.
The drawbacks are:
- Some libraries won't have web support
- The components may not display exactly as they would on a native device
- Some config needed for libraries that aren't transpiled
Some libraries like reanimated require a bit of setup, however I've made it really easy to configure by adding some extra options to the addon. Check out the npm readme for more details.
If those drawbacks aren't dealbreakers then I think you'll be happy with the results.
Create your react native project if you haven't already
npx react-native init AwesomeApp --template react-native-template-typescript
cd AwesomeApp
Initialize Storybook.
npx sb init --type react
You can delete the example stories if you like (not necessary).
rm -rf stories/*
Now add @storybook/addon-react-native-web and it's dependencies
yarn add --dev react-dom react-native-web babel-plugin-react-native-web @storybook/addon-react-native-web
Open up .storybook/main.js and add the addon to the addons list.
module.exports = {
/* existing config */
addons: [/*existing addons,*/ '@storybook/addon-react-native-web'],
};
Now that's the setup done! Lets add a React native component and a story in the stories folder
Here's an example of a button component:
// stories/MyButton.tsx
import React from 'react';
import {StyleSheet, Text, TouchableOpacity, View} from 'react-native';
export type ButtonProps = {
onPress: () => void;
text: string;
color?: string;
textColor?: string;
};
const styles = StyleSheet.create({
button: {
paddingVertical: 8,
paddingHorizontal: 16,
borderRadius: 4,
alignSelf: 'flex-start',
flexGrow: 0,
backgroundColor: 'purple',
},
buttonText: {
color: 'white',
fontSize: 16,
fontWeight: 'bold',
},
buttonContainer: {
alignItems: 'flex-start',
flex: 1,
},
});
export const MyButton = ({text, onPress, color, textColor}: ButtonProps) => (
<View style={styles.buttonContainer}>
<TouchableOpacity
style={[styles.button, !!color && {backgroundColor: color}]}
onPress={onPress}
activeOpacity={0.8}>
<Text style={[styles.buttonText, !!textColor && {color: textColor}]}>
{text}
</Text>
</TouchableOpacity>
</View>
);
And a story for that component:
// stories/MyButton.stories.tsx
import React from 'react';
import {ComponentMeta, ComponentStory} from '@storybook/react';
import {MyButton} from './MyButton';
export default {
title: 'components/MyButton',
component: MyButton,
} as ComponentMeta<typeof MyButton>;
export const Basic: ComponentStory<typeof MyButton> = args => (
<MyButton {...args} />
);
Basic.args = {
text: 'Hello World',
color: 'purple',
};
Now run the Storybook with yarn storybook
and it should open in your browser.
You should see something like this:
Running on the web without a single div or span in sight! 🎉
Thanks for reading this far! Please let me know what you think. You can contact me on twitter at @Danny_H_W or discord in the react-native channel of the storybook discord server.
If you want to see an example project with multiple react native libraries such as reanimated and gesture handler being utilized then checkout this repository.