Tutorials Logic, IN info@tutorialslogic.com
Navigation
Home About Us Contact Us Blogs FAQs
Tutorials
All Tutorials
Services
Academic Projects Resume Writing Website Development
Practice
Quiz Challenge Interview Questions Certification Practice
Tools
Online Compiler JSON Formatter Regex Tester CSS Unit Converter Color Picker
Compiler Tools

Styling in React CSS Modules, Tailwind, Styled: Tutorial, Examples, FAQs & Interview Tips

How Styling Works in React

React does not force one styling solution. A React component is simply a JavaScript function that returns UI, so you can style that UI with regular CSS files, inline styles, CSS Modules, utility-first frameworks like Tailwind CSS, or CSS-in-JS libraries such as styled-components. The best choice depends on team preference, project size, and how much style isolation or dynamic behavior you need.

The important idea is to keep styles maintainable. As components grow, styling decisions affect readability, reuse, naming collisions, and even performance. That is why it helps to understand the trade-offs between the main approaches instead of treating them as interchangeable.

Popular Styling Approaches

ApproachStrengthWeaknessBest fit
Inline stylesSimple for dynamic one-off valuesNo pseudo-classes or media queriesSmall dynamic style objects
Global CSS filesFamiliar and easy to start withClass name conflicts can grow over timeSmall to medium projects
CSS ModulesScoped class names without conflictsSlightly more verbose importsComponent-based apps needing isolation
Styled ComponentsCo-locates styles with components and supports dynamic propsRuntime overhead and different authoring modelTeams that prefer CSS-in-JS
Tailwind CSSFast utility-based styling with consistencyLong class strings if unmanagedDesign systems and utility-first workflows

Example 1: Basic CSS File and Inline Styles

CSS File and Inline Style Example
.card {
    padding: 16px;
    border-radius: 10px;
    border: 1px solid #d0d7de;
    background: #ffffff;
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.06);
}

.card-title {
    margin-bottom: 8px;
    color: #1f2937;
}
import './Card.css'

function Card({ title, children, highlight = false }) {
    return (
        <div
            className="card"
            style={{ borderColor: highlight ? '#2563eb' : '#d0d7de' }}
        >
            <h3 className="card-title">{title}</h3>
            <div>{children}</div>
        </div>
    )
}

This combination is simple and practical. Use CSS classes for most styling, and use inline styles only for small dynamic values such as widths, colors, or transforms that depend directly on props or state.

Example 2: CSS Modules

CSS Modules solve one of the biggest pain points of global CSS: naming collisions. Each class name is scoped to the component file, so you can use common names like button, title, or container without worrying about another file overriding them.

CSS Modules with clsx
.button {
    border: none;
    border-radius: 8px;
    padding: 10px 16px;
    font-weight: 600;
    cursor: pointer;
}

.primary {
    background: #2563eb;
    color: white;
}

.danger {
    background: #dc2626;
    color: white;
}

.disabled {
    opacity: 0.6;
    cursor: not-allowed;
}
import clsx from 'clsx'
import styles from './Button.module.css'

function Button({ label, variant = 'primary', disabled = false }) {
    return (
        <button
            className={clsx(
                styles.button,
                styles[variant],
                { [styles.disabled]: disabled }
            )}
            disabled={disabled}
        >
            {label}
        </button>
    )
}

Example 3: Styled Components

Styled Components is a popular CSS-in-JS library. It allows you to define styles directly in JavaScript and vary them based on props. This can feel natural in component-driven design, especially when themes and prop-based variants are common.

Styled Components Example
import styled from 'styled-components'

const Button = styled.button`
    border: none;
    border-radius: 8px;
    padding: 10px 16px;
    font-weight: 600;
    color: white;
    background: ${props => props.variant === 'danger' ? '#dc2626' : '#2563eb'};

    &:hover {
        opacity: 0.92;
    }

    &:disabled {
        opacity: 0.6;
        cursor: not-allowed;
    }
`

function App() {
    return (
        <div>
            <Button>Save</Button>
            <Button variant="danger">Delete</Button>
        </div>
    )
}

Example 4: Tailwind CSS

Tailwind CSS uses small utility classes instead of writing most component CSS manually. This can speed up UI development and encourage consistent spacing, typography, and color usage across a React project.

Tailwind with clsx and tailwind-merge
import clsx from 'clsx'
import { twMerge } from 'tailwind-merge'

function cn(...inputs) {
    return twMerge(clsx(inputs))
}

function Button({ label, variant = 'primary', disabled = false }) {
    const classes = cn(
        'rounded-md px-4 py-2 font-semibold transition-colors',
        variant === 'primary' && 'bg-blue-600 tl-text-white hover:bg-blue-700',
        variant === 'danger' && 'bg-red-600 tl-text-white hover:bg-red-700',
        disabled && 'cursor-not-allowed opacity-60'
    )

    return (
        <button className={classes} disabled={disabled}>
            {label}
        </button>
    )
}

How to Choose a Styling Approach

  • Use global CSS when the project is small and the team wants a familiar workflow
  • Use CSS Modules when you want scoped styles without moving away from normal CSS
  • Use Styled Components when prop-driven styles and themes are central to the design system
  • Use Tailwind CSS when you prefer utility classes and consistent tokens directly in markup
  • Use inline styles only for small dynamic values, not for full complex styling systems

Common Mistakes

MistakeWhy it causes troubleBetter approach
Putting all styles in one global fileCreates collisions and hard-to-track overridesSplit styles by component or feature
Using inline styles for everythingLoses pseudo-classes, media queries, and maintainabilityReserve inline styles for small dynamic cases
Mixing many styling systems without a ruleMakes the codebase inconsistentChoose a primary approach and use it consistently
Hardcoding design values everywhereMakes design updates difficultUse tokens, variables, or reusable classes

Best Practices

  • Pick a primary styling strategy and use it consistently
  • Keep style decisions close to the component or feature they belong to
  • Prefer reusable tokens for spacing, colors, and typography
  • Use conditional class helpers like clsx when styles depend on props
  • Think about responsiveness, hover states, focus states, and accessibility from the start
  • Avoid class name collisions by using modules or a clear naming system

Summary

React supports many valid styling approaches, and each one has its own trade-offs. Global CSS is simple, CSS Modules provide scoped styles, Styled Components combine styles with component logic, and Tailwind CSS offers a utility-first workflow. The right choice depends on the size of the project, the team's preferences, and the design system needs.

The most important thing is not choosing the trendiest option. It is choosing an approach that keeps your components readable, your styles maintainable, and your UI consistent as the application grows.

Key Takeaways
  • React does not force a single styling approach, so teams can choose what fits their project best.
  • Global CSS is simple but can lead to naming conflicts as an app grows.
  • CSS Modules provide scoped class names and are a strong default for many component-based projects.
  • Styled Components supports prop-based and theme-based styling directly in JavaScript.
  • Tailwind CSS offers a utility-first workflow that can speed up interface development.
  • Inline styles are useful for small dynamic values but not as a full styling strategy.

Ready to Level Up Your Skills?

Explore 500+ free tutorials across 20+ languages and frameworks.