Querying only desktop sections directly in the groq query for a responsive header setup.
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.
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.