How I built a React design system in Storybook

Posted By
Saurabh Jaybhaye

When I joined my first big React project, I didn’t think twice about copy-pasting components. Need a model? Grab it from Project A. Dropdown? Probably lived somewhere in Project B, or maybe it was C. It worked — until it didn’t.
Over time, maintaining UI across different projects became a total mess. Components had random props like isOpenLegacy, styles clashed, and onboarding juniors meant 30-minute calls explaining "what to use and what to ignore." This got me thinking - "There's surely a better way of doing this." And that’s when I found Storybook for React. What started as my attempt to organize a few components ended up as building a full-fledged React Design System. Here's how you can build your own React Design System.
What is a React design system?
A React design system is a structured, documented, and reusable collection of UI components, patterns, and tokens. Mine started small with just a few reusable React components. As I used it, it bloomed into an actual component library in React, with folders, themes, documentation, and testing. And what made it work? Storybook setup for React.
Discovering Storybook for React
I still remember running npx sb init for the first time. Within seconds, I had a playground for my UI. No more spinning up the whole app to test a hover state. No more breaking things to tweak styles.
What Storybook gave me:
- An isolated space to build UI components in React apps
- Live previews with props that I could tweak
- A visual way for others to explore components
- A faster onboarding experience for new devs
- Interactive docs — not just README files
It felt like having my own mini Design System portal. I soon realized that it was more than just a playground. It fixed two of my biggest problems of reusability and visual testing. That’s what really kept me going with the design system.
My first real component: The Accordion
The moment I realized I was creating something helpful was when I transformed a messy, hardcoded Accordion into a clean, flexible, and documented component.
Here's the actual Accordion that kicked it all off:
// Accordion.jsx import { useState } from 'react'; import './Accordion.scss'; const Accordion = ({ title, children }) => { const [open, setOpen] = useState(false); return ( <div className="accordion"> <div className="accordion-header" onClick={() => setOpen(!open)}> <h4>{title}</h4> <span>{open ? '−' : '+'}</span> </div> {open && <div className="accordion-body">{children}</div>} </div> ); }; export default Accordion;
And the accompanying story file in Storybook:
// Accordion.stories.jsx import Accordion from './Accordion'; export default { title: 'Components/Accordion', component: Accordion, argTypes: { title: { control: 'text' }, children: { control: 'text' }, }, }; const Template = (args) => <Accordion {...args} />; export const Default = Template.bind({}); Default.args = { title: 'Click to Expand', children: 'This is the content inside the accordion.', };
This was a game-changer. I could see props live, show interactions, and share the link with teammates instead of explaining how it works over a call.
Structuring my component library in React
At first, everything lived in one folder — and yeah, it got messy fast.
So, I adopted Atomic Design principles and started organizing like this:
src/
components/
atoms/
molecules/
organisms/
Accordion/
Accordion.jsx
Accordion.stories.jsx
This gave my React component library clarity. New components had a home, and I stopped reinventing the wheel every sprint.
Design tokens and theming
Adding themes, such as dark mode, is straightforward to implement. Storybook simplifies this process by using design tokens and themes.
// theme.js export const lightTheme = { primary: '#007bff', background: '#ffffff', text: '#000000', }; export const darkTheme = { primary: '#90caf9', background: '#121212', text: '#ffffff', };
In Storybook’s preview config:
// .storybook/preview.js import { ThemeProvider } from 'styled-components'; import { lightTheme } from './theme'; export const decorators = [ (Story) => ( <ThemeProvider theme={lightTheme}> <Story /> </ThemeProvider> ), ];
The Theme Switcher addon allows you to toggle themes visually, enabling component previews in both light and dark modes without modifying the main application.
Visual testing with Storybook
As the system grew, testing became essential, especially with components like Accordions that had toggles, animations, and hidden content.
Here’s what I used:
- @storybook/test-runner for interaction tests
- Visual testing with Storybook using Chromatic (super cool)
- Jest + Testing Library for unit logic
Visual regression? Caught before they hit production. Props breaking layouts? Spotted during story reviews. No more mystery bugs.
My learnings from using Storybook
This journey taught me a lot about components and also about the process.
- You shouldn't skip documentation: Even if your Accordion is simple today, someone tomorrow may want to know how it works.
- Naming matters: Avoid things like AccordionNewV3FinalFinal.
- Start small: My entire React Design System began with one component.
- Show, don’t tell: Storybook turns explanations into visuals.
Key benefits of my React design system
Building this design system with Storybook brought two standout benefits that made all the difference: visual testing and reusability.
- Visual testing: Using tools like Chromatic and the Storybook test runner means issues like misaligned buttons, broken layouts, or inconsistent states get caught early — before they ever reach production. This gives developers confidence to ship UI updates faster, knowing every component looks and behaves as expected. It reduces regression bugs, saves QA cycles, and keeps the user experience consistent across releases.
- Reusability: The real magic is how reusable components streamline everything. Instead of copy-pasting and fixing styles in every project, we now pull from a single source of truth. This consistency:
- Ensures theme matching across all products in the organization, whether it’s colors, typography, or dark/light modes.
- Saves development time every sprint since we’re reusing components instead of reinventing them.
- Makes onboarding new developers faster — they just check Storybook to understand how a component works instead of digging through random files.
Together, these two benefits not only make the UI more polished and reliable but also speed up delivery, enforce consistency, and reduce long-term maintenance headaches.
If you’re exploring more ways to enhance React applications, don’t miss our blog on Integrating Monaco editor into a React application, where we demonstrate embedding a powerful code editor.
Where I am now (and why it’s better)
I started with chaos, and copy-pasting turned into a solid React Design System powered by Storybook for React.
Now I don’t:
- Copy code between projects
- Repeat explanations about props
- Worry about inconsistent UI
Instead, I say: “Open Storybook and check the Accordion component.” Done.
Building design systems is just one step in creating scalable and maintainable applications. Opcito’s Product Engineering Services help enterprises modernize front-end architectures and deliver consistent user experiences across platforms.
Thinking of starting your own?
If your project is turning into a Frankenstein of UI code, start small. Pick one piece like an Accordion and set it up in Storybook. Build it well. Document it. Let it grow from there. Before you know it, you’ll have your own reusable React components, a living component library in React, and way less pain every time the UI changes. Trust me, future you (and your team) will thank you.