ReactNov 7, 2026 · 6 min read

i ran the hidden div check on my own sites

I read a post this week about React hiding article content inside a div, and I did the thing you do when a post hits close to home: I stopped reading and went to check my own sites. The author had found his Next.js articles parked inside a hidden div at the bottom of the page, invisible to any crawler that does not run JavaScript, and the only reason he knew was that he read the raw HTML instead of looking at the page in a browser. I have a blog and a Next.js app, and I had not run that check on any of them.

The check takes ten seconds. You fetch the raw HTML and look for your heading. If a hidden div sits right before it, your content is parked in the hidden block. This is the command:

terminalTypeScript
curl -sL https://your-site.com/some-page | grep -n 'hidden'

What the hidden div is

The cause is a React option called progressiveChunkSize. React 19.2 started outlining large Suspense boundaries during server rendering. When a boundary is bigger than the limit, 12,800 bytes by default, React parks its finished HTML in a hidden div at the end of the document instead of inlining it where it belongs, and a small inline script swaps it into place when the page loads. The limit counts HTML bytes, not words, so Tailwind classes count toward it. Googlebot runs the script, so Google sees the content. A crawler that does not run JavaScript sees a hidden block at the bottom of the page. You can set progressiveChunkSize to Infinity to opt out, and the React docs note it is already Infinity in renderToString, which does not stream.

My blog: clean

I started with the blog, because it is the site I care most about for search. I curled a full article page and grepped for hidden. Zero hidden divs. The page is about 30KB of HTML, and the article text is all there in the raw bytes. The title shows up five times, the code terms show up five times, and the h1 is right where it should be. That makes sense once I thought about it: the blog is a Vite site with prerendered static HTML. There is no Next.js streaming, no Suspense boundaries for React to outline, so there is nothing to park in a hidden div.

VowReveal: a different problem

Then VowReveal, which is Next.js, so this is where I expected to find it. The landing page has one hidden div, and for a second I thought that was it. Then I looked at what was inside it: nothing. Just React comment markers, an empty shell.

raw HTMLTypeScript
<div hidden=""><!--$--><!--/$--></div>

The real landing content sits inline in the main element, right where it belongs. The hidden div is an empty boundary placeholder, not parked content. Same story on the guest pages, one empty hidden div each. But the guest pages had a different problem, and it was bigger than the hidden div. The raw HTML for a guest page is about 4KB, and it contains no invitation content at all. No couple names, no date, no venue. The body is a loading shell that says Opening your invitation, and a client-resume script fetches the rest after JavaScript loads. So a crawler that does not run JavaScript sees no invitation. The hidden div is empty, so it is not hiding anything. The content just is not in the HTML yet.

That is the honest part. I went looking for the hidden div problem and found a different one instead. So I fixed it, at least for the three demo invitations. A server wrapper plus generateMetadata now puts the couple names, the date, and the venue in the raw HTML and the OG tags, so a share link carries the actual invitation. User-built invitations still wait on Supabase, so those are not fixed yet. The check still did its job, it told me the truth about the bytes, just not the truth I expected.

One more thing I noticed while I was in there: the blog list page is a shell too, about 3KB, with no post titles in the raw HTML. The list renders client-side. Each article page carries its full text, and those are the pages that matter for search, so I am not worried about the list. But it is the same lesson: the page you see in the browser is not the page a crawler sees.

The whole check took ten seconds per page, and it is worth doing on any site you care about for search. Fetch the raw HTML, find your heading, and see what is actually there. The page in your browser will always look fine. The bytes are the ones that tell the truth.