Caelin Sutch Caelin is a passionate product developer, entrepreneur, and visual story teller focused on human-centric design and building beautiful products.

Build a React Native component library with Storybook

5 min read 1537

Building a component UI library is a great way to enforce design standards across an organization or codebase. However, it can come with severe technical roadblocks, especially in large libraries, because it can be easy to end up with a convoluted and hard-to-read codebase.

Thankfully, various tools have been developed to make the component library building process easier. In this article, we’ll be taking a look at some of the tools that make it easier to build component libraries in React Native, primarily Storybook and Shopify Restyle.

React Native has made it easier than ever to create cross-platform and powerful mobile applications using React and Javascript. With tons of community support, React Native also has a healthy ecosystem of plugins and tools that make it easier for software developers to write scalable mobile applications.

First, we’ll be taking a look at Storybook and what it can do for software developers, then dive into creating a very basic component library in React Native using Storybook and a great UI library called Shopify Restyle. At the end of this guide, you’ll have created and documented button and text components.

What is Storyboook?

To understand what Storybook is, we’ll first have to cover what component libraries actually are.

Component libraries are a collection of prebuilt UI components that an entire organization can reuse across multiple projects or screens. Component libraries save product teams time, and make it easier to unit test and individually look at parts of an application.

Storybook is an open source tool for building and documenting UI components in isolation. It makes the process of creating and testing UI components simpler.

Visual depiction of Storybook process

For example, when creating a login page, you’ll likely have several base components like buttons, inputs, and text. Each of these components can be made into a reusable component that you’d then document using Storybook.

Gif of Storybook in use

We made a custom demo for .
No really. Click here to check it out.

Software teams at companies like Google and Atlassian use Storybook to document component libraries across an entire organization to make reusable and sharable codebases.

React Native and Shopify Restyle

Shopify Restyle is an open source styling solution for React Native.

From the Restyle documentation:

The Restyle library provides a type-enforced system for building UI components in React Native with TypeScript. It’s a library for building UI libraries, with themability as the core focus.

With Restyle, it’s easy to build components that are constructed around a central theme. This theme is connected to component styles and props, allowing you to access things like set spacings or colors from props.

For example, to style a button component a certain color, Restyle makes it easy to build the button so you can use <Button color="primary400" /> rather than manually typing out a hex value.

At the core of Restyle is a theme object that you define to contain colors, sizes, spacing, and default styles of all of your components. It also offers two prebuilt components – Box and Text to make it really easy to build larger components.

Setting up the project

Let’s dive into actually building our component library in React Native. We’ll be using Expo in this tutorial for simplicity and Typescript to take advantage of the powerful typing that Restyle offers. I’ve created a repo that has commits that follow along on this project, you can check that out here.

First, lets initialize a new Expo project in the current directory:

npm i -g expo-cli && expo init -t expo-template-blank-typescript

This will prompt you for your application name, then create all the files and install base dependencies for our new application.

Then, we’ll install our dependencies for Storybook and Restyle:

# Setup Storybook for React Native
npx -p @storybook/cli sb init --type react_native

# Install storybook loader to autoload stories
yarn add -D react-native-storybook-loader 

Next, add the following to your package.json to run the storybook loader:

{
  "scripts": {
    "prestorybook": "rnstl"
  }
}

Finally, update your app entry point (App.tsx) to use Storybook:

// App.tsx
import React from 'react';

export { default } from './storybook';

Now, start the storybook server with yarn storybook and start the dev server with yarn ios (or yarn android if you’re running an android emulator.

\Storybook welcome screen with blank mobile app

You should see the above screen. If you don’t, close all the running processes, then start storybook and the dev server again.

Congrats! You now have an Expo project set up with Storybook!

Let’s take a look at our files. If you look in the root directory, you’ll see a new folder called storybook with a child folder called stories. This is where the Storybook and stories are configured.

You can see in the Storybook webpage above that we have two stories, the Button story with two variants, with text and with some emoji, then the Welcome story with variant to Storybook.

Let’s now start building out our own component library using Restyle! In this next part, we’ll be setting up the Restyle theme, then building a new Button component using the Box and Text components.

Configuring Restyle

First, install Restyle: yarn add @shopify/restyle.

Next, we’ll set up a core theme for our application.

Create a new file, src/theme.ts and put the following in it:

// src/theme.ts

import { createTheme } from '@shopify/restyle'

const palette = {
  purpleLight: '#8C6FF7',
  purplePrimary: '#5A31F4',
  purpleDark: '#3F22AB',

  greenLight: '#56DCBA',
  greenPrimary: '#0ECD9D',
  greenDark: '#0A906E',

  black: '#0B0B0B',
  white: '#F0F2F3',
};


const theme = createTheme({
  colors: {
    primary: palette.purplePrimary,
    ...palette
  },
  spacing: {
    s: 8,
    m: 16,
    l: 24,
    xl: 40,
  },
  breakpoints: {
    phone: 0,
    tablet: 768,
  },
});

export type Theme = typeof theme;
export default theme;

Then, wrap your app in the Restyle theme provider by updating App.tsx:

// App.tsx

import React from 'react';
import {ThemeProvider} from '@shopify/restyle';

import Storybook from './storybook';
import theme from './src/theme';

const App = () => (
  <ThemeProvider theme={theme}>
    <Storybook/>
  </ThemeProvider>
);

export default App;

If you restart your app, you’ll probably notice no change, but we’ve successfully configured our App to use Restyle! Let’s now create our Box, Text, and Button components.

Lets create our Components folder using Bash:

mkdir -p ./src/Components

First, lets create our Box component in src/Components/Box.tsx:

// Box.tsx
import {createBox} from '@shopify/restyle';
import {Theme} from '../theme';

const Box = createBox<Theme>();

export default Box;

Then, our Text component in src/Components/Text.tsx:

// Text.tsx
import {createText} from '@shopify/restyle';
import {Theme} from '../theme';

const Text = createText<Theme>();

export default Text;

Finally, we’ll create our Button component in src/Components/Button.tsx:

// Button.tsx
import React from "react";
import { BoxProps, TextProps } from "@shopify/restyle";
import { ActivityIndicator, TouchableHighlight } from "react-native";
import { Theme } from "../theme";
import Box from "./Box";
import Text from "./Text";

type ButtonProps = {
  onPress: () => void;
  loading?: boolean;
  textProps?: TextProps<Theme>;
} & Partial<BoxProps<Theme>>;

const Button: React.FC<ButtonProps> = ({
  children,
  onPress,
  loading,
  textProps,
  ...props
}) => (
  <TouchableHighlight underlayColor="transparent" onPress={onPress}>
    <Box
      py="m"
      px="xl"
      backgroundColor="primary"
      borderRadius={8}
      shadowOffset={{ height: 2, width: 0 }}
      shadowRadius={5}
      shadowColor="black"
      shadowOpacity={0.2}
      {...props}
    >
      {loading ? (
        <ActivityIndicator color="white" />
      ) : (
        <Text color="white" {...textProps}>
          {children}
        </Text>
      )}
    </Box>
  </TouchableHighlight>
);

export default Button;

Now let’s point out a few awesome things that we’re doing with our Box and Text components. Notice how we’re using props like py and backgroundColor in our Box component. We’re passing in values that we’ve defined in our theme, like m for spacing or primary for our button color, which is pretty cool!

Now that we have these components built out, lets export all these components in src/Components/index.ts:

// index.ts
export { default as Button } from './Button';
export { default as Text } from './Text';

Now, let’s update our stories so we can see these in Storybook.

First, we’ll delete storybook/stories/Welcome and storybook/stories/Button to get rid of this story we don’t need and update storybook/stories/index.js to be just *import* './Button.stories';.

Create storybook/stories/Button.stories.js:

// Button.stories.js

import React from 'react';
import { action } from '@storybook/addon-actions';
import { text } from '@storybook/addon-knobs';
import { storiesOf } from '@storybook/react-native';
import { Button, Text } from '../../src/Components';
import CenterView from './CenterView';

storiesOf('Button', module)
  .addDecorator((getStory) => <CenterView>{getStory()}</CenterView>)
  .add('with text', () => (
    <Button onPress={action('clicked-text')}>
      <Text>{text('Button text', 'Hello Button')}</Text>
    </Button>
  ))
  .add('with some emoji', () => (
    <Button onPress={action('clicked-emoji')}>
      <Text>😀 😎 👍 💯</Text>
    </Button>
  ))
  .add('loading', () => (
    <Button onPress={action('loading')} loading>
      <Text>Test</Text>
    </Button>
  ));

Now, if you look at our Storybook, you should see some nice pretty buttons!

Example mobile app with Storybook and a button with emojis

Conclusion

Now, you have a basic component library built with Expo, Storybook, and Restyle! If you want to learn more about Restyle, I recommend reading the Restyle documentation. You can also find the finished code repository here.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Caelin Sutch Caelin is a passionate product developer, entrepreneur, and visual story teller focused on human-centric design and building beautiful products.

2 Replies to “Build a React Native component library with Storybook”

  1. Good instructions, but a very old version of Storybook (5.3) is used. The current version is >v6.3 :/

  2. Hey great article! I’ve just released a new alpha of 6.0 react native storybook. Get in touch with me please if you’d like to try it out and give your feedback :). In the new alpha CSF, Controls and Args are all implemented.

Leave a Reply