Design System in React Native with Storybook

Storybook Logo

📡 What you will learn

  • Setup Storybook with React Native.
  • Writing .stories to debug your application with isolated components.

👾 Before we start the exercise

👨‍🚀 Exercise 4

  • Setup Storybook
npx sb@latest init --type react_native

🔭 Hint: Read the prompt, the setup is NOT 100% automated.

? We were not able to detect the right builder for your project. Please select one: ›
// answer Webpack

Render Storybook

Change App.tsx for Storybook in React Native

  • Change the entry point of your application and comment your default export to return Storybook's UI.
// App.tsx

...

// eslint-disable-next-line import/no-default-export
// export default App;    <------ comment this for now

// return Storybook's UI
export { default } from "./.storybook";
  • Update your package.json to run storybook with npm run storybook:
    "storybook-generate": "sb-rn-get-stories",
    "storybook-watch": "sb-rn-watcher",
++    "storybook": "sb-rn-get-stories && expo start"
  • Run your app, you should have the Storybook displayed like this:
Storybook React Native first launch

Adding your own stories

Right now, storybook display components created for testing purposes. We want to add our own components and follow the principle of colocation.

Place code as close to where it's relevant as possible

  • Delete generated Button.stories.js files:
rm -rf .storybook/stories/
  • Update .storybook/main.js file to load stories from our components folder:
module.exports = {
--  // stories: ['./stories/**/*.stories.?(ts|tsx|js|jsx)'],
++  stories: ["../src/components/**/*.stories.?(ts|tsx|js|jsx)"],
};
  • Create a new file ./src/components/Text.stories.tsx:
// ./src/components/Text.stories.tsx

import React from "react";
import { View } from "react-native";
import { Text } from "react-native-paper";

export default {
  title: "Text",
};

export const Default = () => (
  <View style={{ padding: 16, justifyContent: "space-between", flex: 1 }}>
    <Text variant="displayLarge">Display Large</Text>
    <Text variant="displayMedium">Display Medium</Text>
    <Text variant="displaySmall">Display small</Text>

    <Text variant="headlineLarge">Headline Large</Text>
    <Text variant="headlineMedium">Headline Medium</Text>
    <Text variant="headlineSmall">Headline Small</Text>

    <Text variant="titleLarge">Title Large</Text>
    <Text variant="titleMedium">Title Medium</Text>
    <Text variant="titleSmall">Title Small</Text>

    <Text variant="bodyLarge">Body Large</Text>
    <Text variant="bodyMedium">Body Medium</Text>
    <Text variant="bodySmall">Body Small</Text>
  </View>
);

Default.story = {
  name: "Default",
};
  • Create a new Button.stories.tsx and add all types of buttons when mode is 'text' | 'outlined' | 'contained'
// ./src/components/Button.stories.tsx

import React from "react";
import { View } from "react-native";
import { Button } from "react-native-paper";

export default {
  title: "Button",
};

export const Default = () => (
  <View style={{ padding: 16, justifyContent: "space-between", flex: 1 }}>
    {/* import buttons from https://callstack.github.io/react-native-paper/docs/components/Button/ */}
  </View>
);

Default.story = {
  name: "Default",
};
  • Create a Card.stories.tsx

👽 Bonus