Using CSS Media Queries in React with Fresnel

Build SSR-compatible responsive React applications with the Fresnel library for seamless breakpoint detection and component-level responsive rendering

Introduction

Modern web applications demand responsive designs that work seamlessly across all devices. While CSS media queries have been the foundation of responsive web design for years, implementing them effectively in React applications--particularly with server-side rendering (SSR)--presents unique challenges.

The Fresnel library, created by Artsy, offers an elegant solution that brings the power of CSS media queries to React while maintaining full SSR compatibility. This guide explores how to leverage Fresnel for building responsive React applications that perform exceptionally well and avoid the common pitfalls of client-side only responsive implementations.

When implementing responsive designs at scale, consider how your approach integrates with your overall web development strategy to ensure consistent user experiences across all platforms and devices.

What You'll Learn

  • How Fresnel solves SSR responsive design challenges
  • Installation and configuration steps
  • Creating and using breakpoint components
  • Performance optimization strategies
  • Advanced patterns and best practices
Why Use Fresnel for Responsive React?

Key benefits of implementing Fresnel in your React applications

SSR Compatibility

Responsive logic executes on the server, delivering correctly styled content from the first request without layout shifts.

TypeScript Support

Full TypeScript definitions included for type-safe development with IDE autocompletion and compile-time checking.

Framework Integration

Works seamlessly with Next.js, Gatsby, and other React frameworks using static or hybrid rendering approaches.

Component-Based API

Intuitive Media components for conditional rendering based on viewport size, integrated naturally into your React codebase.

Installation and Setup

Getting started with Fresnel requires installing the package and configuring your application to use its components. The library supports both JavaScript and TypeScript projects, with full TypeScript definitions included for type-safe development.

Installing Fresnel

npm install @artsy/fresnel

Or with yarn:

yarn add @artsy/fresnel

Configuring the MediaQueryProvider

Once installed, wrap your application with the MediaQueryProvider component. This provider manages media query matching and makes breakpoint information available to child components through React context.

import { MediaQueryProvider, createMediaQueryMatcher } from '@artsy/fresnel'

const breakpoints = {
 mobile: '(max-width: 767px)',
 tablet: '(min-width: 768px) and (max-width: 1024px)',
 desktop: '(min-width: 1025px)'
}

function App({ children }) {
 return (
 <MediaQueryProvider
 createMediaQueryMatcher={createMediaQueryMatcher}
 breakpoints={breakpoints}
 defaultBreakpoint="desktop"
 >
 {children}
 </MediaQueryProvider>
 )
}
Defining TypeScript Breakpoints
1import { Breakpoints } from '@artsy/fresnel'2 3// Define your design system's responsive breakpoints4export const appBreakpoints: Breakpoints<{5 mobile: '(max-width: 767px)'6 tablet: '(min-width: 768px) and (max-width: 1024px)'7 desktop: '(min-width: 1025px)'8 wide: '(min-width: 1440px)'9}> = {10 mobile: '(max-width: 767px)',11 tablet: '(min-width: 768px) and (max-width: 1024px)',12 desktop: '(min-width: 1025px)',13 wide: '(min-width: 1440px)'14}15 16// Usage in MediaQueryProvider17<MediaQueryProvider18 createMediaQueryMatcher={createMediaQueryMatcher}19 breakpoints={appBreakpoints}20 defaultBreakpoint="desktop"21>

Using Media Components

The Media component serves as the primary building block for conditional rendering based on viewport size. It renders children only when the specified breakpoint condition is met, enabling powerful responsive patterns.

Basic Media Component Usage

import { Media } from '@artsy/fresnel'

function Navigation() {
 return (
 <nav>
 <Media at="mobile">
 <MobileMenu />
 </Media>
 <Media at="tablet">
 <TabletNavigation />
 </Media>
 <Media at="desktop">
 <DesktopNavigation />
 </Media>
 </nav>
 )
}

Range-Based Matching

The Media component supports greaterThan and lessThan props for flexible range matching:

<Media greaterThan="mobile">
 <Sidebar />
</Media>

<Media lessThan="desktop">
 <CollapsedPanel />
</Media>

<Media greaterThan="mobile" lessThan="desktop">
 <TabletSpecificContent />
</Media>
Complete Fresnel Implementation Example
1import React from 'react'2import { Media, MediaQueryProvider, createMediaQueryMatcher } from '@artsy/fresnel'3 4const breakpoints = {5 mobile: '(max-width: 767px)',6 tablet: '(min-width: 768px) and (max-width: 1024px)',7 desktop: '(min-width: 1025px)'8}9 10function ResponsiveLayout() {11 return (12 <div className="layout">13 <Media at="mobile">14 <div className="single-column">15 <MobileHeader />16 <MobileContent />17 </div>18 </Media>19 20 <Media at="tablet">21 <div className="two-column">22 <TabletHeader />23 <div className="content-grid">24 <MainContent />25 <SecondaryContent />26 </div>27 </div>28 </Media>29 30 <Media at="desktop">31 <div className="three-column">32 <DesktopHeader />33 <div className="content-grid">34 <Sidebar />35 <MainContent />36 <SecondaryContent />37 </div>38 </div>39 </Media>40 </div>41 )42}43 44// App wrapper45function App() {46 return (47 <MediaQueryProvider48 createMediaQueryMatcher={createMediaQueryMatcher}49 breakpoints={breakpoints}50 defaultBreakpoint="desktop"51 >52 <ResponsiveLayout />53 </MediaQueryProvider>54 )55}

Server-Side Rendering Considerations

Implementing Fresnel correctly in an SSR environment requires understanding how the library handles viewport detection on the server. Since server environments lack a physical viewport, Fresnel needs additional configuration to determine which breakpoints should be active during rendering.

Preventing Hydration Mismatches

Hydration mismatches occur when server-rendered HTML differs from what React would produce during hydration. Fresnel addresses this by using a default breakpoint for server rendering that matches the expected initial client state.

// Next.js example with custom server-side detection
import { MediaQueryProvider, createMediaQueryMatcher } from '@artsy/fresnel'

const breakpoints = {
 mobile: '(max-width: 767px)',
 tablet: '(min-width: 768px) and (max-width: 1024px)',
 desktop: '(min-width: 1025px)'
}

function MyApp({ Component, pageProps }) {
 return (
 <MediaQueryProvider
 createMediaQueryMatcher={createMediaQueryMatcher}
 breakpoints={breakpoints}
 defaultBreakpoint="desktop"
 >
 <Component {...pageProps} />
 </MediaQueryProvider>
 )
}

// The defaultBreakpoint ensures consistent SSR rendering

Best Practices for SSR

  1. Use consistent defaults: Choose a default breakpoint that represents your most common user experience
  2. Test across devices: Verify rendering on various viewport sizes during development
  3. Monitor hydration: Watch for React warnings about mismatched content
  4. Defer client-only logic: Keep client-specific viewport detection separate from SSR rendering

For applications where SEO performance is critical, implementing proper SSR with Fresnel ensures search engines receive fully rendered content from the first request. Combined with professional SEO services, this approach maximizes your site's visibility and search rankings.

Performance Optimization Strategies

While Fresnel adds JavaScript for responsive logic, the library is designed with performance in mind. Understanding how its reactivity system works helps you write even more performant responsive code.

Minimizing Re-renders

Components using Media components re-render when breakpoint conditions change. To minimize unnecessary re-renders:

  • Place Media components at appropriate tree levels
  • Group related responsive elements under single Media wrappers
  • Use React.memo for components that don't need to update
import React, { memo } from 'react'
import { Media } from '@artsy/fresnel'

// Memoize to prevent unnecessary re-renders
const ResponsiveContent = memo(function ResponsiveContent({ data }) {
 return (
 <Media at="desktop">
 <DesktopView data={data} />
 </Media>
 )
})

// Parent component re-renders when props change,
// but ResponsiveContent only re-renders on breakpoint transitions

Bundle Size Optimization

Fresnel is relatively small, but consider these optimizations:

  • Import only the components you need
  • Enable tree shaking in your bundler
  • Evaluate whether all features are necessary

When building performant web applications, the combination of efficient responsive implementations like Fresnel and a solid web development framework creates fast, user-friendly experiences that drive engagement and conversions.

Advanced Patterns and Best Practices

Custom Hooks for Responsive Logic

Create reusable hooks to encapsulate responsive logic:

import { useContext } from 'react'
import { MediaContext } from '@artsy/fresnel'

export function useBreakpoint() {
 const mediaState = useContext(MediaContext)
 return mediaState || {}
}

// Usage
function MyComponent() {
 const { at, greaterThan } = useBreakpoint()
 
 if (at('mobile')) {
 return <MobileView />
 }
 return <DesktopView />
}

Combining with CSS Layout Systems

Fresnel's component-based approach complements CSS Grid and Flexbox:

  • Use Media for structural changes (column count, component visibility)
  • Use CSS for fine-grained layout adjustments (spacing, alignment)
  • Let CSS handle what it does best while Fresnel handles structural logic

Custom Media Components

Create domain-specific Media components for common patterns:

import { Media } from '@artsy/fresnel'

function ShowOnDesktop({ children }) {
 return <Media at="desktop">{children}</Media>
}

function ShowOnMobile({ children }) {
 return <Media at="mobile">{children}</Media>
}

// Usage
<ShowOnDesktop>
 <Sidebar />
</ShowOnDesktop>

Fresnel vs Other Approaches

Comparison with Alternatives

ApproachProsConsBest For
FresnelSSR-compatible, component-based, TypeScript supportAdds JS bundle sizeSSR applications, Next.js/Gatsby
react-responsivePopular, similar APISSR support requires extra setupStandard React apps
CSS Media QueriesZero JS overhead, native browser supportNo component-level controlSimple responsive styling
Styled ComponentsCSS-in-JS integrationLimited SSR without careful setupProjects already using CSS-in-JS

When to Choose Fresnel

Choose Fresnel when:

  • Building SSR applications with Next.js or Gatsby
  • Needing component-level conditional rendering
  • Requiring consistent SSR/client rendering
  • Wanting type-safe responsive code with TypeScript

Consider simpler alternatives when:

  • Building purely client-side SPAs
  • Only needing CSS-based responsive styles
  • Bundle size is the primary concern

Frequently Asked Questions

Does Fresnel work with Next.js App Router?

Yes, Fresnel works with both Next.js Pages and App Router. For App Router, wrap your layout or page components with MediaQueryProvider. Ensure the provider is inside any client/server boundary to maintain SSR compatibility.

How does Fresnel affect SEO?

Fresnel improves SEO by ensuring search engines see correctly rendered content from the first request. Since SSR renders the correct breakpoint-specific content, crawlers receive complete, properly structured HTML without requiring JavaScript execution. For comprehensive SEO optimization, consider partnering with our [SEO specialists](/services/seo-services/) who understand the technical requirements of modern web applications.

Can I use Fresnel with CSS Modules?

Absolutely. Fresnel handles component-level responsive logic while CSS Modules manages styling. Use Media components to conditionally render elements, then apply CSS Modules classes for layout and visual styling.

What happens if JavaScript is disabled?

With Fresnel's SSR rendering, users without JavaScript see the content rendered for the default breakpoint. For full fallback support, consider also implementing CSS media queries as a progressive enhancement.

How do I debug breakpoint issues?

Use browser developer tools to simulate different viewports and monitor React re-renders. Add console logs in your Media components to track which breakpoints are active. The React DevTools browser extension also shows component hierarchy and props.

Conclusion

Implementing responsive designs in React applications, especially those using server-side rendering, requires careful consideration of how breakpoints are detected and applied. Fresnel provides a powerful solution that brings CSS media query patterns to React components while maintaining full SSR compatibility.

By defining breakpoints as React components and managing their state through the MediaQueryProvider, you can create responsive applications that render correctly from the first request and maintain consistent behavior across all devices. The library's integration with popular frameworks like Next.js and Gatsby makes it accessible to a wide range of projects.

Start implementing Fresnel today:

  1. Install the package: npm install @artsy/fresnel
  2. Define breakpoints matching your design system
  3. Wrap your application with MediaQueryProvider
  4. Replace conditional rendering with Media components
  5. Test across devices and optimize performance

With Fresnel as part of your responsive design toolkit, you're equipped to create React applications that adapt beautifully to every viewport. Ready to elevate your web development projects? Our web development team has extensive experience building performant, responsive applications using modern React technologies.

Ready to Build Modern React Applications?

Our team specializes in creating performant, responsive web applications using the latest React technologies and best practices.