Next.js (V15, App router, SSR) does not render HTML as initially structured.
It renders <template> tags inside the structure, and further in the source, the content in a hidden <div>.
Thus, there is no structure in the source HTML, all attempts to be semantically correct are quite vain: all you see before JS is an empty structure and then a bunch of unstructured data.
Isn't that a problem for accessibility and/or SEO?
Is it taken for granted that JS will be ran by search engines and a11y tools? Then why even bother doing SSR?
Here are two examples of what Next.js (V15, App router) renders as the initial HTML for server components.
Main content:
JSX
<body>
<main id="main">
{children}
</main>
</body>
Renders:
<body>
<main id="main">
<template id="P:1"></template><!--$--><!--/$--><!--$--><!--/$-->
</main>
<!-- ... -->
<!-- This is supposed to be #main content -->
<div hidden id="S:1">
<div>
<div class="cards-scroller-titles"></div>
<div class="cards-scroller">
<div class="card"><h1 class="card-title">À propos</h1>
<div class="about-grid">
<section class="presentation">
<div class="">
<div><span><p>Je suis développeur freelance, basé sur Nantes et spécialisé en <strong>Symfony</strong>, <strong>architecture back-end</strong>, <strong>React/Next.js</strong> et <strong>intégration soignée</strong>.</p>
<!-- ... -->
</body>
Some components:
JSX:
<ul className="section-content">
{data.parcours.map((job: string) =>
<TimedItem item={job}/>
)}
</ul>
Renders:
<ul class="section-content">
<li class="timed-item">
<time class="date">
<template id="P:14"></template>
</time>
<h4 class="title">
<template id="P:15"></template>
</h4>
</li>
<li class="timed-item">
<time class="date">
<template id="P:16"></template>
</time>
<h4 class="title">
<template id="P:17"></template>
</h4>
</li>
</ul>
<!-- ... -->
<div hidden id="S:14">2010+</div>
<script>$RS("S:14", "P:14")</script>
<div hidden id="S:15">Développeur / architecte web freelance</div>
<script>$RS("S:15", "P:15")</script>
<div hidden id="S:16">2010+</div>
<script>$RS("S:16", "P:16")</script>
<div hidden id="S:17">Contributions à des projets open-source (modules Symfony, plugins PhpStorm, Mastodon...)</div>
<script>$RS("S:17", "P:17")</script>
<div hidden id="S:18">2006 — 2012</div>