If you can't solve by using mediaqueries and you must display two different components rather than the same styled. The workaround to solve this is to check what is the window size at the rendered time and show one layout or another. It would create a minimum delay (insignificant if cached) before the header is shown but this is the only way I am able to guess.
So, using Gatsby's default structure in <Layout> component you should have something like that:
return (
<>
<Header siteTitle={data.site.siteMetadata.title} />
<div>
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</div>
</>
)
So, in your <Header> component you should check your window size and render one component or another:
export const Header = (props) => {
let currentWidth;
if (typeof window !== 'undefined') currentWidth = useWindowWidth();
return typeof window !== 'undefined' ? currentWidth >= 768 ? <DesktopPane /> : <MobilePane /> : null;
};
As you can see, in the return I check if window is defined in a ternary chained condition. If the window is not defined (i.e: is undefined) it returns a null. If it's defined, it checks the current window's width (currentWidth) and there's another ternary condition that displays the mobile or the desktop menu.
As a best practice, chained ternaries are not the cleanest solution, they are difficult to read and maintain but for now, the solution works (and of course it must be refactored).
In this case, useWindowWidth() is a custom hook that calculates in every window the size but you can use whatever you like. It looks like:
import {useEffect, useState} from 'react';
const getWidth = () => window.innerWidth
|| document.documentElement.clientWidth
|| document.body.clientWidth;
export const useWindowWidth = () => {
let [width, setWidth] = useState(getWidth());
useEffect(() => {
let timeoutId = null;
const resizeListener = () => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => setWidth(getWidth()), 150);
};
window.addEventListener('resize', resizeListener);
return () => {
window.removeEventListener('resize', resizeListener);
};
}, []);
return width;
};
Code provided by: https://usehooks.com/useWindowSize/
Note that it's common in Gatsby's projects to check if the window is !== than undefined due to the point you argued. At the compilation/build point isn't defined yet. You can check for further information about Debugging HTML Builds in their documentation.