Skip to content

Instantly share code, notes, and snippets.

@dannyhw
Last active July 5, 2022 16:19
Show Gist options
  • Select an option

  • Save dannyhw/8752965fed92217a316471e11b92bdf2 to your computer and use it in GitHub Desktop.

Select an option

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 acessibility of your UI.

Storybook started off web focused and has expanded to many different platforms since then. One of those platforms is React Native.

React Native provides a way for javascript developers to develop for IOS and Android whilst using tools they are familar with. In fact react native actually supports much more than just the mobile platform. There is also support for Web, Windows, MacOS and even VR.

A different take on Storybook for React Native

I've been working on a new approach of using storybook with react-native that is intended to be an alternative or complementary addition to the react native storybook space.

rnsb.mp4

The challenge of React Native

React native has it's own storybook implementation at @storybook/react-native however it has some limitations. This stems from the fact that most things need to be reimplemented for the platform.

What is means in practice is that the storybook UI and almost all Addon UI has to be recreated 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 web platform. This also means that external tools like visual testing for storybook need a custom implementation in order to support react native.

All this has lead to an incomplete experience for react native when compared with the web. It still has it's uses, and I personally see a lot of potential with react native storybook. The problem is that 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 in the web.

The project that I want to show you should help bridge the gap today. Meaning you can have the full functionality that you know and love from storybook in the web platform.

Disclaimer: 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 usecases 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 as a website for others to see. The best part is that since it's running in the web with the reactjs config most addons should work with no changes necessary.

That means:

  • Much better UI/UX
  • Popular addons such as Docs supported out of the box
  • Chromatic and other visual testing tools supported
  • Easily share with stake holders 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

The setup is as follows.

Setup your react native project if you haven't already

npx react-native init AwesomeApp --template react-native-template-typescript
cd AwesomeApp

Initialize the react 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 thats the setup done! Lets add a React native component and a story in the stories folder

Heres 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 storybook with yarn storybook and it should open in your browser.

You should see something like this: image

Running in 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