Designing React Components in Tailwind

This article highlights some essential tips for creating reusable React components with Tailwind CSS, while also following best practices for component creation.

Written by

Thijs Verreck

Published on

Let me start by saying: I love Tailwind. Tailwind CSS empowers frontend developers, like me, to quickly turn design concepts into functional designs. It shines in component-based frameworks like React, allowing developers to style interfaces directly within their markup, eliminating the need for traditional CSS or CSS-in-JS. This focus enhances both the functionality and reliability of applications. This article outlines some key strategies that I use for building reusable React components with Tailwind CSS, adhering to component design best practices.

What is Tailwind CSS and Why Use It?

Tailwind CSS is a utility-first framework that lets you apply CSS properties directly to your HTML, enabling a highly customizable style approach by combining utility classes.

Unlike UI-first frameworks that offer pre-designed components, Tailwind CSS provides more flexibility, allowing developers to tailor components to project-specific requirements.

Here’s an example of a CTA link button using Tailwind CSS in HTML:

1<a href="#" class="text-white bg-sky-500 border-0 py-3 px-8 focus:outline-none hover:bg-sky-600 rounded-full text-lg mt-10 sm:mt-0">
2  A Link Button
3</a>

Writing Better React Components

The best practice is to avoid premature abstraction; start with simple markup and refine into components as your application's structure becomes clearer. Tailwind CSS supports this iterative approach by allowing rapid styling changes within a single file.

Choosing the Right Component API

A well-designed component API enhances code quality and maintainability. Here are some guidelines:

  • Explicit UI States: Define UI states clearly to avoid invalid state combinations.
  • Avoid CSS Classes as Props: This can obscure the component's state and lead to bugs.
  • Local vs. Global State: Manage state locally unless synchronization across components is needed.
  • Prefer Props Over State: Use props to increase component flexibility and reusability.
  • Simplify Component APIs: Use distinct components for different variations rather than overloading a single component with multiple responsibilities.
  • Functional vs. Class Components in React
  • Functional components are generally preferred for their simplicity and compatibility with React Hooks, though class components may be necessary for complex state management or lifecycle control.
  • Testing with a Badge Component

Here’s how you can create a Button component in React and Tailwind CSS, demonstrating the use of TypeScript for type safety:

1enum ButtonVariant {
2  PRIMARY, SECONDARY, SUCCESS, DANGER
3}
4
5enum ButtonSize {
6  LARGE, MEDIUM, SMALL
7}
8
9const SIZE_MAPS: Record<ButtonSize, string> = {
10  [ButtonSize.SMALL]: 'px-4 py-2 text-sm',
11  [ButtonSize.MEDIUM]: 'px-6 py-3 text-base',
12  [ButtonSize.LARGE]: 'px-8 py-4 text-lg',
13};
14
15const VARIANT_MAPS: Record<ButtonVariant, string> = {
16  [ButtonVariant.PRIMARY]: 'bg-blue-500 text-white hover:bg-blue-600',
17  [ButtonVariant.SECONDARY]: 'bg-gray-500 text-white hover:bg-gray-600',
18  [ButtonVariant.SUCCESS]: 'bg-green-500 text-white hover:bg-green-600',
19  [ButtonVariant.DANGER]: 'bg-red-500 text-white hover:bg-red-600',
20};
21
22type ButtonProps = {
23  variant: ButtonVariant;
24  children?: React.ReactNode;
25  size: ButtonSize;
26};
27
28export default function Button({ children, variant, size }: ButtonProps) {
29  const buttonClasses = `inline-flex items-center justify-center font-medium leading-none rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 ${VARIANT_MAPS[variant]} ${SIZE_MAPS[size]}`;
30  return <button className={buttonClasses}>{children}</button>;
31}
32
33Button.defaultProps = {
34  variant: ButtonVariant.PRIMARY,
35  size: ButtonSize.MEDIUM,
36};

Conclusion

For me, the combination of React and Tailwind CSS provide a powerful combination for building modern, component-based web applications with streamlined styling capabilities. This allows developers to create highly reusable components that integrate seamlessly into any project.

Ship your next UI in 5 minutes.

Prototyper is the fastest way to build, test, and ship products used by 500+ designers, frontend engineers and product managers.