Querying only desktop sections directly in the groq query for a responsive header setup.

2 replies
Last updated: Jan 24, 2024
In my header setup, I have an array of sections for desktop and an array of sections for mobile(allows for a lot of customization). Is there a way I could only query the desktop sections when my screen is bigger than 767px directly in the groq query? I'm using Next.js app router and I'm not wanting to turn the entire header into a client component by checking the width that way.
AI Update

GROQ doesn't have access to client-side information like screen width - it runs on the server and queries your content data, not browser state. However, you have a few good options for handling this in Next.js App Router while keeping your header as a server component.

Best Approach: Server-Side Device Detection

Since you're using Next.js App Router, you can detect the device type server-side using the userAgent from headers, which keeps your component as a server component:

import { headers } from 'next/headers'

async function Header() {
  const headersList = await headers()
  const userAgent = headersList.get('user-agent') || ''
  
  // Simple mobile detection
  const isMobile = /mobile|android|iphone/i.test(userAgent)
  
  // Query only the sections you need
  const query = `*[_type == "header"][0]{
    ${isMobile ? 'mobileSections' : 'desktopSections'}
  }`
  
  const data = await client.fetch(query)
  
  return <header>{/* render sections */}</header>
}

This approach:

  • Keeps your header as a server component
  • Reduces payload by only fetching the sections you need
  • Uses native Next.js APIs without external dependencies

Alternative: Query Both, Render Conditionally

If you prefer to query both arrays and conditionally render them (useful for responsive designs that need both), you can use CSS to hide/show sections:

const data = await client.fetch(`*[_type == "header"][0]{
  desktopSections,
  mobileSections
}`)

return (
  <header>
    <div className="hidden md:block">{/* desktop sections */}</div>
    <div className="md:hidden">{/* mobile sections */}</div>
  </header>
)

This loads both but lets CSS handle the display logic, which is better for responsive designs where the breakpoint might not be exactly 767px on all devices.

Note on User-Agent Detection

User-agent detection isn't perfect - tablets might be classified incorrectly, and some browsers send non-standard user-agent strings. For most use cases, the CSS approach is more reliable. Use server-side detection when you specifically need to reduce the initial payload size or have distinct mobile/desktop content structures.

The key insight is that GROQ parameters are great for passing dynamic values into queries, but they can't access browser/viewport information since GROQ runs on the server before any client-side JavaScript executes.

that approach may make for a ton of queries in the event of a browser changing size.
Typically in the event of a header/footer or general site settings, it's best to query once from the server side and setup responsiveness using the front-end.
Oh wow, didn't even think of that haha. I'm sure that would have made my usage go up a bunch. Thank you!

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?