Skip to content

Generated Section Index Pages#

View Markdown

When ssg.sectionIndex is enabled, the SSG build walks collected pages and the file tree. For each directory that has child pages and no existing index route (index.md, index.mdx, or an already generated directory index), it writes a themed landing page that lists those children as cards or a list.

The listing honors frontmatter title (falling back to the filename). Theme chrome — navigation, search, sidebar — comes from the same generateHtmlPage path as ordinary pages. Existing index.md / index.mdx files are never overwritten.

The feature is off unless you turn it on. Existing sites stay unchanged.

import { oxContent } from "@ox-content/vite-plugin";

export default {
  plugins: [
    oxContent({
      ssg: {
        sectionIndex: true,
      },
    }),
  ],
};

false or omitted writes nothing. true enables card listings. An object enables the feature and overrides only the fields you set:

oxContent({
  ssg: {
    sectionIndex: {
      style: "list",
    },
  },
});
Option Type Default
ssg.sectionIndex boolean / SectionIndexOptions false
style "list" / "cards" "cards"

What gets generated#

Given this tree and no guide/index.md:

content/
  index.md
  guide/
    a.md
    b.md

the build writes dist/guide/index.html. Child titles come from frontmatter when present:

---
title: Install
---

# Install

If title is omitted, the filename is formatted (getting-started.md → "Getting Started"). Nested directories that themselves have pages appear as a single child that links to that directory's index (authored or generated).

Root index.md is left alone. A directory whose only children are drafts or unlisted pages does not get a generated index.

Existing indexes are kept#

If guide/index.md or guide/index.mdx already exists, that page is the section landing page. The generator skips the directory even when the option is on. The same is true when a permalink already claims the directory URL.

Do not rely on this feature to wrap or replace an authored index. Write the Markdown you want, or omit index.md and let the listing be generated.

Drafts, unlisted pages, and hostile input#

Children with draft: true or unlisted: true are omitted from the listing, even when publishState is off. Scheduled / expired pages follow publishState when that option is enabled.

Titles, descriptions, and hrefs are escaped. javascript:, data:, vbscript:, file:, and protocol-relative // hrefs are dropped from the markup. Attribute breakouts such as "/guide" onclick="alert(1)" are escaped so they cannot leave the href attribute.

Cards use the .ox-section-index class. List style uses .ox-section-index--list. Bare mode still runs the same escape and href rules when the listing HTML is passed through generateHtmlPage.

Last updated: