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
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>
)
}
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>
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
- Use consistent defaults: Choose a default breakpoint that represents your most common user experience
- Test across devices: Verify rendering on various viewport sizes during development
- Monitor hydration: Watch for React warnings about mismatched content
- 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
| Approach | Pros | Cons | Best For |
|---|---|---|---|
| Fresnel | SSR-compatible, component-based, TypeScript support | Adds JS bundle size | SSR applications, Next.js/Gatsby |
| react-responsive | Popular, similar API | SSR support requires extra setup | Standard React apps |
| CSS Media Queries | Zero JS overhead, native browser support | No component-level control | Simple responsive styling |
| Styled Components | CSS-in-JS integration | Limited SSR without careful setup | Projects 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:
- Install the package:
npm install @artsy/fresnel - Define breakpoints matching your design system
- Wrap your application with MediaQueryProvider
- Replace conditional rendering with Media components
- 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.