
# Collection & Markdown Pages

Three properties turn one page definition into many routes, or replace the component tree with prose: `collection` fans out over table records, `markdown` renders a body from a file, and `contentDir` fans out over a directory of files.

## `collection`

A `collection` block generates one route per record. The page's `path` must carry a dynamic segment, and `slugField` names the field whose value fills it.

| Property    | Description                                              |
| ----------- | -------------------------------------------------------- |
| `table`     | **Required.** Table to generate pages from.              |
| `slugField` | **Required.** Field whose value becomes the URL segment. |
| `filter`    | Conditions limiting which records generate a page.       |

```yaml
pages:
  - name: Blog Post
    path: /blog/:slug
    collection:
      table: posts
      slugField: slug
      filter:
        - { field: published, operator: eq, value: true }
    rss: { limit: 20 }
    components:
      - { type: text, tag: h1, content: '$record.title' }
      - { type: text, content: '$record.body', props: { format: markdown } }
```

The generated record is exposed as `$record.*` to the whole tree, including `meta` — so per-record SEO comes for free. A URL matching no record returns `404`.

## `markdown`

Render the page body from markdown instead of components.

| Property  | Description                                                                                 |
| --------- | ------------------------------------------------------------------------------------------- |
| `content` | Inline markdown string.                                                                     |
| `file`    | Path to a markdown file, resolved from the project root. Mutually exclusive with `content`. |
| `layout`  | Wrapper style: `prose` (default), `docs`, `full`, or `none`.                                |
| `toc`     | Table of contents — `true`, or `{ maxDepth, position }`.                                    |

`toc.maxDepth` is 1–6; `toc.position` is `top` or `sidebar`.

```yaml
pages:
  - name: Docs Home
    path: /docs
    markdown:
      file: content/docs/home.md
      layout: docs
      toc: { maxDepth: 3, position: sidebar }
```

YAML frontmatter between `---` delimiters is parsed and exposed as `$frontmatter.*`, usable in `meta` and sibling properties. Rendered markdown HTML is sanitized, consistently with the `text` and `alert` content components.

## `contentDir`

`contentDir` is a **page-level** property. It fans one page definition out over every markdown file in a directory and derives a navigation sidebar from their frontmatter — the way this documentation is built.

| Property           | Description                                                                          |
| ------------------ | ------------------------------------------------------------------------------------ |
| `directory`        | **Required.** Directory holding the markdown files.                                  |
| `slugFrom`         | **Required.** Derive the slug from `filename` or `filepath`.                         |
| `include`          | Glob filtering which files are picked up, e.g. `*.md`.                               |
| `index`            | Slug served at the collection's base path, making it the section's front door.       |
| `sort`             | `{ field, order }` — order entries by a frontmatter field, `asc` or `desc`.          |
| `filter`           | Frontmatter key/value conditions restricting which files become pages.               |
| `nav`              | Sidebar derived from the collection (see below).                                     |
| `editUrl`          | Template for a per-article "edit this page" link. `{lang}` and `{slug}` interpolate. |
| `issueUrl`         | Template for a per-article "report an issue" link.                                   |
| `contributionNote` | Prose rendered in the contribution footer.                                           |

`nav` accepts `enabled`, `groupBy` (the frontmatter key that buckets articles into sidebar groups), `labelFrom` (the frontmatter key supplying each link's label), plus `groupLabels`, `groupIcons`, `collapsed` and `tabs` for presentation.

```yaml
pages:
  - name: docs
    path: /docs/:slug
    contentDir:
      directory: content/docs
      slugFrom: filename
      include: '*.md'
      index: introduction
      sort: { field: order, order: asc }
      nav: { enabled: true, groupBy: section, labelFrom: sidebarLabel }
    markdown:
      layout: docs
      toc: { maxDepth: 3, position: sidebar }
    components:
      - { type: container, element: header }
```

:::callout
**`contentDir` is not a component source.** It sits beside `components` on the page, not inside one. The page's own `markdown` block then styles every generated article — one `layout` and `toc` decision covers the whole directory.
:::

## Related Pages

- [Pages Overview](/en/docs/pages-overview) — the full page property table.
- [Routing & Paths](/en/docs/pages-routing) — the dynamic segment a collection fills.
- [SEO & Metadata](/en/docs/seo-meta) — per-record and per-article metadata.
- [Content Components](/en/docs/content-components) — inline markdown fragments.
- [llms.txt](/en/docs/llms-txt) — the machine-readable index derived from content directories.
