How to Make Tabs, Accordions and “Read More” Content Crawlable

Why content in tabs, accordions and "read more" sections is invisible to many crawlers when it loads on click, and four fixes with code for HTML, React and Next.js.

Content inside tabs, accordions and “read more” sections is crawlable when it is present in the page’s HTML on first load and only hidden visually. It is not crawlable, for most AI crawlers, when it is fetched from the server after a click. Google has said for years that content hidden in tabs for usability is indexed and treated normally in mobile-first indexing, but that only applies if the content is in the HTML. The fix is to render every panel on the server and use HTML attributes or CSS to show one at a time.

The two kinds of hidden content

Pattern In the HTML on load? Readable by crawlers that skip JavaScript?
All panels rendered, inactive ones hidden with CSS or the hidden attribute Yes Yes
Native <details> and <summary> accordion Yes Yes
Panel content fetched from an API when the tab is clicked No No
“Load more” button that fetches the next items No No
Full text rendered, shortened with CSS behind “read more” Yes Yes

Check your pages first

  1. Open the page and choose “View page source” (not “Inspect”).
  2. Search for a sentence that only appears in the second or third tab, or inside a closed accordion.
  3. If it is missing, that content is loaded after a click.

Our AI crawler access checker also compares the words a crawler receives with what a browser receives.

Fix 1: use the native details element for accordions

<details>
  <summary>How long does migration take?</summary>
  <p>A migration of under 200 pages usually takes two to four weeks, including testing.</p>
</details>

The answer is in the HTML, keyboard and screen-reader support are built in, and no JavaScript is needed. Style it with CSS to match your design.

Fix 2: render all tab panels, show one

In React or Next.js, render every panel and hide the inactive ones with the hidden attribute, instead of rendering only the active panel:

// Tabs.jsx: all panels are in the HTML; only the active one is visible
"use client";
import { useState } from "react";

export default function Tabs({ tabs }) {
  const [active, setActive] = useState(0);
  return (
    <div>
      <div role="tablist">
        {tabs.map((t, i) => (
          <button key={t.id} role="tab" aria-selected={i === active}
                  aria-controls={`panel-${t.id}`} onClick={() => setActive(i)}>
            {t.label}
          </button>
        ))}
      </div>
      {tabs.map((t, i) => (
        <section key={t.id} id={`panel-${t.id}`} role="tabpanel" hidden={i !== active}>
          {t.content}
        </section>
      ))}
    </div>
  );
}

Pass the tab content in from a server component, so it is part of the server-rendered HTML. A client component is still rendered to HTML on the server in Next.js; the problem only appears when the content itself is fetched in the browser.

Fix 3: shorten long text with CSS, not with a fetch

.read-more { display: -webkit-box; -webkit-line-clamp: 4; -webkit-box-orient: vertical; overflow: hidden; }
.read-more.is-open { -webkit-line-clamp: unset; }

The full text stays in the HTML; the button only toggles a class.

Fix 4: make “load more” crawlable

Keep a real paginated URL behind every “load more” button, such as /blog/page/2/, and link to it with an anchor tag. JavaScript can intercept the click for a smooth experience, while crawlers follow the link.

What about hidden=”until-found”?

The HTML attribute hidden=”until-found” hides content but lets the browser’s find-in-page reveal it. It is supported in Chromium-based browsers. The content is in the HTML, so crawlers can read it, but check browser support for your audience before relying on it for interaction.

When loading on click is fine

Content that has no search value, such as a login form, a personal dashboard or a live stock widget, can load on demand. The rule applies to content you want found and quoted: answers, prices, specifications, FAQs and reviews.

Frequently asked questions

Does Google give less weight to content hidden in tabs?

Google has said that, with mobile-first indexing, content hidden for usability reasons such as tabs is treated like visible content, as long as it is in the HTML.

Is display:none bad for SEO?

Not when it is used for normal interface patterns like tabs. Hiding content to show different text to search engines than to users is against Google’s spam policies.

Do AI assistants read closed accordions?

Crawlers read the HTML, so if the text is there, they can use it. What an assistant quotes depends on the question.

Sources

  1. Google Search Central, “Mobile-first indexing best practices”
  2. MDN Web Docs, the details element and the hidden attribute
  3. Google Search Central, “Understand the JavaScript SEO basics”