How to Create Responsive React Components

Make React components responsive with Tailwind breakpoints, CSS Modules media queries, and a useMediaQuery hook. Build one card that adapts.

6 min read

Responsive React components change their layout at viewport breakpoints instead of shipping a separate design per device. The core idea is mobile-first: write the small-screen layout as the default, then add styles that only apply at wider breakpoints.

Start with the mobile layout

A mobile-first component uses unprefixed styles for the smallest screens. Wider breakpoints then override those styles, so the simple layout is the base and complexity is added upward.

In Tailwind, unprefixed utilities apply everywhere, while a prefixed utility such as md: only applies at the md breakpoint of 48rem and above. The default breakpoints are documented in the Tailwind responsive guide.

Add Tailwind breakpoints

A profile card stacks vertically on mobile, then lays out side by side on medium screens and larger. The default styles handle mobile, and the md: prefixes add the desktop arrangement.

App.jsxApp.jsx
function ProfileCard() {
  return (
    <div className="mx-auto max-w-md rounded-xl bg-white p-4 shadow-md md:flex md:max-w-2xl md:items-center md:gap-4">
      <img className="h-24 w-24 rounded-full object-cover" src="/avatar.jpg" alt="Portrait of Ada" />
      <div className="mt-4 text-center md:mt-0 md:text-left">
        <h2 className="text-lg font-semibold text-gray-900">Ada Lovelace</h2>
        <p className="text-gray-600">Computing pioneer and mathematician.</p>
      </div>
    </div>
  );
}

On a phone the image sits above a centered block of text. Past 48rem the md:flex turns the card into a row, md:items-center vertically centers the text, and md:text-left returns it to left alignment. The card still needs the setup in the Tailwind walkthrough before these classes take effect.

The same idea with CSS Modules

CSS Modules write the identical mobile-first logic as plain media queries. The default rules handle mobile, and a min-width query adds the wider layout.

csscss
/* ProfileCard.module.css */
.card {
  padding: 16px;
  text-align: center;
}
@media (min-width: 768px) {
  .card {
    display: flex;
    align-items: center;
    gap: 16px;
    text-align: left;
  }
}

The component imports the module and uses the generated class name. Vite maps each class to a unique name at build time, so the styles stay scoped to this component.

App.jsxApp.jsx
import styles from "./ProfileCard.module.css";
 
function ProfileCard() {
  return <div className={styles.card}>Profile content</div>;
}

The browser applies the same breakpoint behavior as the Tailwind version. The only difference is syntax: a media query block versus prefixed utility classes.

Respond in JavaScript with a hook

CSS covers layout, but sometimes React itself must know the viewport, for example to render a different structure or pass a flag to a library. A useMediaQuery hook wraps the browser matchMedia API and returns a boolean that tracks whether a media query currently matches.

App.jsxApp.jsx
const isDesktop = useMediaQuery("(min-width: 768px)");

The component can then branch on isDesktop during render. Building the hook correctly, including cleanup of the media query listener, is covered in the useMediaQuery hook article.

Container queries for component-level responsiveness

Breakpoints respond to the viewport, but a reusable component often cares about the space its parent gives it. Tailwind v4 adds container queries with the @container class and variants such as @md: that activate based on the container width instead of the page width.

Container queries make a card respond to its own column, which is useful when the same component appears in a sidebar and a wide hero. They are a newer CSS feature, so confirm browser support before relying on them alone.

Keep it accessible

Responsive design should reflow content without hiding it. Text must remain readable at every width, touch targets should stay large enough to tap, and a layout change should not remove keyboard or screen reader access.

The same class-based thinking extends to dark mode, where a single toggle restyles every component.

Rune AI

Rune AI

Key Insights

  • Write the mobile layout as the default styles.
  • Add Tailwind breakpoints with prefixes like md: and lg:.
  • Use media queries in CSS Modules for the same effect in plain CSS.
  • Use a useMediaQuery hook only when JavaScript needs the breakpoint.
  • Container queries adapt a component to its parent width.
RunePowered by Rune AI

Frequently Asked Questions

Should I use a media query or a JavaScript hook?

Use CSS media queries for layout and styling. Reach for a useMediaQuery hook only when React must know the breakpoint, such as rendering a different structure or wiring a library.

Do Tailwind breakpoints replace CSS media queries?

Tailwind breakpoints compile into the same CSS media queries. They are a shorter syntax, not a different mechanism, so you can mix them with plain CSS.

What is mobile-first in React?

Mobile-first means the small-screen styles are the default, and larger breakpoints add overrides. This keeps the simplest layout as the base and reduces the styles that must be overridden.

Conclusion

Responsive React components start mobile-first and add breakpoints that only activate on wider screens. Tailwind prefixes and CSS Modules media queries both compile to the same media queries, and a JavaScript hook is for the few cases where React must know the viewport.