Building Reusable React Components with styled-components

Jazim Abbas
Bits and Pieces
Published in
6 min readNov 12, 2023

--

Introduction

In the ever-evolving landscape of web development, the quest for efficient, maintainable, and stylish UI components is perpetual. While libraries like Chakra UI offer fantastic pre-built solutions, there comes a point in many projects where a bespoke touch is not just desirable but necessary.

In this article, we’ll embark on a journey to create a reusable button component using styled-components. We’ll unravel the simplicity and power that comes with crafting your own design system, exploring the freedom it provides in tailoring components to fit your project like a glove. Join us as we dive into the world of styled-components and discover how investing time in your design system can be a game-changer for your React applications.

Let’s get started! 🚀

Why Reusable Components?

In the bustling realm of web development, imagine having a magic wand for consistent design, easy maintenance, and scalable projects. That wand? Reusable components. 🌟

  1. Consistency is Key: Reusable components bring order to chaos, ensuring that buttons, cards, and forms all speak the same visual language. No more design dissonance!.
  2. Ease of Maintenance: Update once, apply everywhere. With reusable components, making changes becomes a breeze. Say goodbye to hunting down every instance of a style tweak.
  3. Scalability: As your project grows, so does the need for scalability. Reusable components are the building blocks that allow you to expand without losing your mind.

Think of them as LEGO bricks for your UI. 🧱 Whether you’re building a small application or a sprawling platform, reusable components are the glue that holds everything together. Embrace the simplicity, save time, and make your development journey a smoother ride! 🚗💨.

Creating a Button Component

Now, let’s take a stroll through the process of crafting a button component that’s not just a button but a versatile building block for your user interface.

I drew inspiration from the enchanting world of Chakra UI. Just like Chakra’s button, our button embraces simplicity with props like variant, size, and colorScheme. It's a nod to user-friendly design, making our button a seamless addition to the Chakra UI family. Let's sprinkle some of that Chakra magic into our creation! 🌟🎨

To make the component usable as a package and even updatable from any repository, let’s start by creating it as a Bit component.

Install Bit:

npx @teambit/bvm install

Create a new Bit workspace with a reusable React development environment included (you can add other envs, to support other types of components, if needed):

bit new react my-workspace --env teambit.react/react-env

Create a new React component named ‘button’:

bit create react button

Update the button component with the following base styles:

import { css } from "styled-components";
import { boxShadowColor } from "./utils";

export const baseStylesConfig = css`
font-weight: 500;
padding: 1.8rem 2rem;
box-shadow: 0px 10px 20px ${boxShadowColor};
border-radius: 6px;
border: none;
cursor: pointer;
text-decoration: none;
color: #fff;
display: block;
text-align: center;

&:disabled {
opacity: 0.6;
cursor: none;
pointer-events: none;
}

&:hover {
background-color: var(--light-color);
}
`;

In styled-components, “styled” is a function used to create styled components with dynamic styles, while “css” is a helper function for defining static styles that can be reused within styled components.

For every Individual props, we’ll create a separate “css” utilities so that we can easily extend our functionality.

Size Prop

import { css } from "styled-components";

export const sizes = {
md: css`
min-width: 178px;
height: 56px;
font-size: 1.6rem;
`,
sm: css`
padding: 10px 20px;
`,
};

You can very easily extend this to further. You can very easily add new sizes e.g. lg, xl, 2xl etc…

Variant Prop

import { css } from "styled-components";

export const variants = {
solid: css`
background-color: var(--color);
`,
outline: css`
color: var(--color);
border: 1px solid var(--color);
`,
};

Color or Theme Prop

import { css } from "styled-components";

export const colors = {
primary: css`
--color: #2664f5;
--light-color: #3a6eea;
`,
};

Putting Everything Together

import { ReactNode } from "react";
import styled from "styled-components";
import { baseStylesConfig } from "./base";
import { sizes } from "./sizes";
import { colors } from "./colors";
import { variants } from "./variants";

type Props = {
size?: keyof typeof sizes;
color?: keyof typeof colors;
variant?: keyof typeof variants;
children: ReactNode;
};

type StyledButtonProps = {
$size: Props["size"];
$color: Props["color"];
$variant: Props["variant"];
};

const StyledButton = styled.button<StyledButtonProps>`
${baseStylesConfig};
${(p) => sizes[p.$size]};
${(p) => colors[p.$color]};
${(p) => variants[p.$variant]};
`;

export const Button = ({
size = "md",
color = "primary",
variant = "solid",
...rest
}: Props & any) => {
return <StyledButton
$size={size}
$color={color}
$variant={variant}
{...rest}
/>;
};

This is just a one way to create this component. I think it is neat and clean code. And you can very easily extend this to any level. It might be some code duplication especially in the TypeScript types e.g. Props & StyledButtonProps.

The reason I am using $ prefix in the custom styled-component props, because there is a new feature introduced by styled-components i.e. Transient Props. This will basically not rendered to the DOM. If I don’t use Transient Props, then you need to manually mention which props should be forwarded to underlying DOM and which not.

Install missing dependencies

To install any dependencies your component might need, run:

bit install --add-missing-deps

Previewing components

Run the workspace UI to preview your component:

bit start

Sharing components

Create a scope on bit.cloud and set your components to use that scope. For example, if your account name is my-org and scope name is my-scope run the following:

bit scope set my-org.my-scope

Run the following to share your components:

bit tag -m "my first version of button" && bit export

Imagine having your own design playground. That’s the magic of a DIY Design System! 🎨✨

  1. Total Control: You become the captain of your style ship. No more compromises — every button, color, and spacing is precisely how you want it.
  2. Lean and Mean: Forget bloat. With a DIY system, you only bring in what you need. Smaller bundles mean faster load times. Hello, speed!
  3. Tailored to You: Your project is unique, so why settle for one-size-fits-all? A DIY design system lets you tailor components to match your project’s personality.
  4. Future-Proofing: As your project evolves, so can your design system. Adapt and grow without being tied to someone else’s roadmap.

In a nutshell, DIY design systems offer freedom, speed, and a touch of bespoke charm to your development journey. Time to make your design dreams a reality! 🚀💡

In the tapestry of web development, we’ve woven a custom thread, crafting a button that mirrors our project’s essence. Drawing inspiration from Chakra UI, we’ve witnessed the power of reusable components and the beauty of a DIY design system.

As you embark on your design journey, remember: the initial investment in creating your components pays off in spades. Enjoy the freedom, flexibility, and tailored touch that comes with being the architect of your design destiny.

So, armed with your button component and the wisdom of a DIY design system, go forth and create interfaces that not only look good but feel uniquely yours. Happy coding! 🌐💻✨

Closing Thoughts

Your Insights on Better Reusable Component Implementation or Design are Welcome! Share your ideas to enrich our understanding. If you have any elegant solutions or suggestions, we’d love to hear them.

For those who wish to support, consider buying me a coffee. Thank you for your time and encouragement. Happy Coding!

--

--