Skip to content

Instantly share code, notes, and snippets.

@dannyhw
Last active July 5, 2022 16:19
Show Gist options
  • Save dannyhw/8752965fed92217a316471e11b92bdf2 to your computer and use it in GitHub Desktop.
Save dannyhw/8752965fed92217a316471e11b92bdf2 to your computer and use it in GitHub Desktop.
draft document about a new react native web addon

Intro

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.

A different take on Storybook for React Native

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

The challenge of React Native

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.

Storybook + React Native Web

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.

Is this realistic?

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.

Introducing @storybook/addon-react-native-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.

The setup

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: image

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment