DEV Community

Cover image for Building Scalable and Reusable React Components with Tailwind CSS
Rowsan Ali
Rowsan Ali

Posted on

2

Building Scalable and Reusable React Components with Tailwind CSS

In modern web development, building scalable and reusable components is important for maintaining a clean and efficient codebase. React, with its component-based architecture, is a perfect fit for this purpose. When combined with Tailwind CSS, a utility-first CSS framework, you can create highly customizable and maintainable UI components. In this blog post, we'll explore how to build scalable and reusable React components using Tailwind CSS, complete with code examples.

Table of Contents

  1. Introduction to React and Tailwind CSS
  2. Setting Up a React Project with Tailwind CSS
  3. Building a Reusable Button Component
  4. Creating a Scalable Card Component
  5. Using Props for Customization
  6. Extending Components with Variants
  7. Conclusion

Introduction to React and Tailwind CSS

React

React is a JavaScript library for building user interfaces. It allows you to create reusable UI components that can be composed to build complex UIs. React's component-based architecture promotes reusability and separation of concerns, making it easier to manage and scale large applications.

Tailwind CSS

Tailwind CSS is a utility-first CSS framework that provides low-level utility classes for building custom designs without writing CSS from scratch. It allows you to style your components directly in your HTML (or JSX), making it easier to create responsive and customizable UIs.

Setting Up a React Project with Tailwind CSS

Before we start building components, let's set up a new React project with Tailwind CSS.

  1. Create a new React project:
   npx create-react-app my-tailwind-app
   cd my-tailwind-app
Enter fullscreen mode Exit fullscreen mode
  1. Install Tailwind CSS:
   npm install tailwindcss postcss autoprefixer
Enter fullscreen mode Exit fullscreen mode
  1. Initialize Tailwind CSS:
   npx tailwindcss init
Enter fullscreen mode Exit fullscreen mode
  1. Configure tailwind.config.js:
   module.exports = {
     content: [
       './src/**/*.{js,jsx,ts,tsx}',
     ],
     theme: {
       extend: {},
     },
     plugins: [],
   }
Enter fullscreen mode Exit fullscreen mode
  1. Add Tailwind to your CSS:

Create a src/index.css file and add the following:

   @tailwind base;
   @tailwind components;
   @tailwind utilities;
Enter fullscreen mode Exit fullscreen mode
  1. Import the CSS file in src/index.js:
   import './index.css';
Enter fullscreen mode Exit fullscreen mode
  1. Start the development server:
   npm start
Enter fullscreen mode Exit fullscreen mode

Now that our project is set up, let's start building some reusable components.

Building a Reusable Button Component

Let's start by creating a simple reusable button component. This button will have different styles based on its type (e.g., primary, secondary).

  1. Create a Button.js file:
   import React from 'react';

   const Button = ({ children, type = 'primary', onClick }) => {
     const baseStyles = 'px-4 py-2 font-semibold rounded focus:outline-none';
     const primaryStyles = 'bg-blue-500 text-white hover:bg-blue-600';
     const secondaryStyles = 'bg-gray-500 text-white hover:bg-gray-600';

     const styles = type === 'primary' ? primaryStyles : secondaryStyles;

     return (
       <button className={`${baseStyles} ${styles}`} onClick={onClick}>
         {children}
       </button>
     );
   };

   export default Button;
Enter fullscreen mode Exit fullscreen mode
  1. Using the Button component:
   import React from 'react';
   import Button from './Button';

   function App() {
     return (
       <div className="p-4">
         <Button type="primary" onClick={() => alert('Primary Button Clicked!')}>
           Primary Button
         </Button>
         <Button type="secondary" onClick={() => alert('Secondary Button Clicked!')}>
           Secondary Button
         </Button>
       </div>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

In this example, the Button component is highly reusable and customizable. You can easily add more types or styles by extending the type prop and corresponding styles.

Creating a Scalable Card Component

Next, let's create a scalable card component that can be used to display various types of content.

  1. Create a Card.js file:
   import React from 'react';

   const Card = ({ title, description, imageUrl, children }) => {
     return (
       <div className="max-w-sm rounded overflow-hidden shadow-lg">
         {imageUrl && <img className="w-full" src={imageUrl} alt={title} />}
         <div className="px-6 py-4">
           <div className="font-bold text-xl mb-2">{title}</div>
           <p className="text-gray-700 text-base">{description}</p>
         </div>
         {children && <div className="px-6 pt-4 pb-2">{children}</div>}
       </div>
     );
   };

   export default Card;
Enter fullscreen mode Exit fullscreen mode
  1. Using the Card component:
   import React from 'react';
   import Card from './Card';

   function App() {
     return (
       <div className="p-4">
         <Card
           title="Card Title"
           description="This is a simple card component built with Tailwind CSS."
           imageUrl="https://via.placeholder.com/300"
         >
           <button className="bg-blue-500 text-white px-4 py-2 rounded">
             Learn More
           </button>
         </Card>
       </div>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

The Card component is designed to be flexible and scalable. You can pass different props like title, description, and imageUrl to customize its content. Additionally, you can include any child elements within the card, making it highly reusable.

Using Props for Customization

Props are a powerful way to customize and extend your components. Let's enhance our Button component to accept more props for further customization.

  1. Extend the Button component:
   import React from 'react';

   const Button = ({ children, type = 'primary', size = 'medium', onClick }) => {
     const baseStyles = 'font-semibold rounded focus:outline-none';
     const primaryStyles = 'bg-blue-500 text-white hover:bg-blue-600';
     const secondaryStyles = 'bg-gray-500 text-white hover:bg-gray-600';

     const sizeStyles = {
       small: 'px-2 py-1 text-sm',
       medium: 'px-4 py-2 text-base',
       large: 'px-6 py-3 text-lg',
     };

     const styles = `${baseStyles} ${type === 'primary' ? primaryStyles : secondaryStyles} ${sizeStyles[size]}`;

     return (
       <button className={styles} onClick={onClick}>
         {children}
       </button>
     );
   };

   export default Button;
Enter fullscreen mode Exit fullscreen mode
  1. Using the enhanced Button component:
   import React from 'react';
   import Button from './Button';

   function App() {
     return (
       <div className="p-4">
         <Button type="primary" size="small" onClick={() => alert('Small Button Clicked!')}>
           Small Button
         </Button>
         <Button type="secondary" size="large" onClick={() => alert('Large Button Clicked!')}>
           Large Button
         </Button>
       </div>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

By adding more props like size, we can further customize the Button component, making it even more reusable and adaptable to different use cases.

Extending Components with Variants

Sometimes, you may want to create components with multiple variants (e.g., different colors, sizes, or styles). Let's extend our Button component to support multiple variants.

  1. Define variants in Button.js:
   import React from 'react';

   const Button = ({ children, variant = 'primary', size = 'medium', onClick }) => {
     const baseStyles = 'font-semibold rounded focus:outline-none';
     const sizeStyles = {
       small: 'px-2 py-1 text-sm',
       medium: 'px-4 py-2 text-base',
       large: 'px-6 py-3 text-lg',
     };

     const variantStyles = {
       primary: 'bg-blue-500 text-white hover:bg-blue-600',
       secondary: 'bg-gray-500 text-white hover:bg-gray-600',
       danger: 'bg-red-500 text-white hover:bg-red-600',
       success: 'bg-green-500 text-white hover:bg-green-600',
     };

     const styles = `${baseStyles} ${variantStyles[variant]} ${sizeStyles[size]}`;

     return (
       <button className={styles} onClick={onClick}>
         {children}
       </button>
     );
   };

   export default Button;
Enter fullscreen mode Exit fullscreen mode
  1. Using the Button component with variants:
   import React from 'react';
   import Button from './Button';

   function App() {
     return (
       <div className="p-4">
         <Button variant="primary" onClick={() => alert('Primary Button Clicked!')}>
           Primary Button
         </Button>
         <Button variant="danger" onClick={() => alert('Danger Button Clicked!')}>
           Danger Button
         </Button>
         <Button variant="success" onClick={() => alert('Success Button Clicked!')}>
           Success Button
         </Button>
       </div>
     );
   }

   export default App;
Enter fullscreen mode Exit fullscreen mode

By defining different variants, we can easily create buttons with various styles without duplicating code. This approach makes our components more maintainable and scalable.

Conclusion

Building scalable and reusable React components with Tailwind CSS is a powerful way to create maintainable and customizable UIs. By leveraging React's component-based architecture and Tailwind's utility-first approach, you can build flexible and efficient components that can be easily extended and reused across your application.

In this blog post, we covered:

  • Setting up a React project with Tailwind CSS.
  • Building a reusable Button component.
  • Creating a scalable Card component.
  • Using props for customization.
  • Extending components with variants.

Sentry blog image

How to reduce TTFB

In the past few years in the web dev world, we’ve seen a significant push towards rendering our websites on the server. Doing so is better for SEO and performs better on low-powered devices, but one thing we had to sacrifice is TTFB.

In this article, we’ll see how we can identify what makes our TTFB high so we can fix it.

Read more

Top comments (0)

AWS Security LIVE!

Join us for AWS Security LIVE!

Discover the future of cloud security. Tune in live for trends, tips, and solutions from AWS and AWS Partners.

Learn More

Instrument, monitor, fix: a hands-on debugging session

Join Lazar for a hands-on session where you’ll build it, break it, debug it, and fix it. You’ll set up Sentry, track errors, use Session Replay and Tracing, and leverage some good ol’ AI to find and fix issues fast.

Tune in to the full event

DEV is partnering to bring live events to the community. Join us or dismiss this billboard if you're not interested. ❤️