Skip to content

Next.js – Expected server HTML to contain a matching in

Live example available here

I’m trying to make a basic layout where, on mobiles, only the latest posts appear. On desktop, the left column should be the posts and the right column the top categories and most popular posts.

Here is the layout:

const IndexLayout: React.FC<IndexLayoutProps> = ({}) => {
  const cols = useScreenType()

  return cols === '2-cols' ? (
    <div className="w-full flex justify-between items-start">
      <ListPosts data-comp="ListPosts" className="w-4/6" />
      <div className="sticky ml-12 w-2/6 flex flex-col">
        <TopCategories data-comp="TopCategories" className="w-full" />
        <PopularPosts data-comp="PopularPosts" className="mt-4" />
      </div>
    </div>
  ) : (
    <ListPosts data-comp="ListPosts" className="w-full" />
  )
}

Here’s the useScreenType hook:

import { useMediaQuery } from 'react-responsive'

export const useScreenType = () => {
  const is2Cols = useMediaQuery({ minWidth: 1300 })
  const is1Cols = useMediaQuery({ minWidth: 800 })

  if (is2Cols) {
    return '2-cols'
  }

  if (is1Cols) {
    return '1-cols'
  }

  return 'fullscreen'
}

And I keep getting this error:

Warning: Expected server HTML to contain a matching <div> in <div>.
div
[email protected]:///./components/posts/ListPosts.tsx:31:19
div
[email protected]:///./components/layout/IndexLayout.tsx:28:149
div
[email protected]:///./pages/index.tsx:24:149
[email protected]:///./node_modules/@apollo/client/react/context/ApolloProvider.js:13:18
[email protected]:///./node_modules/next-apollo/dist/index.es.js:26:1911
div
div
[email protected]:///./pages/_app.tsx:37:19
[email protected]:///./node_modules/@next/react-dev-overlay/lib/internal/ErrorBoundary.js:23:47
[email protected]:///./node_modules/@next/react-dev-overlay/lib/internal/ReactDevOverlay.js:73:20
[email protected]:///./node_modules/next/dist/client/index.js:155:20
[email protected]:///./node_modules/next/dist/client/index.js:643:18
[email protected]:///./node_modules/next/dist/client/index.js:779:19

Now I think the issue is due to the useScreenType hook not being able to get a width because window isn’t defined on the server. But how can I fix this issue? And not only do I get an error, but my HTML renders weirdly.

The final render ends up being something like this (when it renders as ‘2-cols’):

<div class="flex flex-col justify-start items-start w-full">
  <div class="mt-6 w-full"></div>
  <div class="mt-4 flex items-center cursor-pointer transform transition hover:scale-105 text-sm">
    <div class="w-full p-6 rounded-lg flex flex-col dark:bg-gray-800 shadow-md"></div>
    <div class="mt-4 p-6 rounded-lg flex flex-col dark:bg-gray-800 shadow-md"></div>
  </div>
</div>

Note: I am using Next.js v10.2.0

Code can be found on GitHub

Answer

For anyone wondering how I fixed this, I ditched the responsive design with logic and switched to CSS. Here is my layout post fix (changed some classes with the lg prefix [documentation]):

const IndexLayout: React.FC<IndexLayoutProps> = ({}) => {
  return (
    <div className="mt-12 lg:mt-24 w-5/6 mx-auto flex items-start">
      <div className="w-full flex justify-between items-start">
        <ListPosts className="lg:w-4/6 w-full" />
        <div className="hidden sticky ml-12 w-2/6 lg:flex flex-col">
          <TopCategories className="w-full" />
          <PopularPosts className="mt-4" />
        </div>
      </div>
    </div>
  )
}