Configure your site
On this page
You can build a useful site with the files created by docsprout init. Change one thing at a time, run docsprout check, and keep the last working version in Git when possible.
The three configuration files
| File | What it controls | When you need it |
|---|---|---|
docs/docsprout.json | Project identity, appearance and home-page presentation | Created by init |
docs/layout.json or docs/layout.md | Published pages, navigation order, home page and unlisted policy | init creates JSON; Markdown is optional |
docs/versions.json | Published release history | Only for a historical site |
The generated files use JSON. Keep the commas, quotation marks and braces exactly paired. Each JSON file starts with "schema_version": 1; leave that value alone. If the punctuation is wrong, docsprout check names the file and error.
Project metadata and colours
Edit docs/docsprout.json:
{
"schema_version": 1,
"project": {
"name": "MyLibrary-FP",
"description": "Useful Pascal tools"
},
"theme": {
"preset": "teal"
}
}
project.name appears in the header and browser page title. project.description becomes each generated page’s description metadata; it is not ordinary visible page text. docsprout init may add project.repository_url from a GitHub remote. An http(s) repository_url becomes the home page hero’s Repository action; project.site_url is metadata only and DocSprout does not render it anywhere. Add an identity.links entry when readers should be able to follow a visible project link.
The supported colour presets are blue, teal, ocean and purple. Start with a preset. You can choose exact colours later in Themes.
Pages, home page and navigation
Your navigation layout decides what is public. Navigation is the ordered list of published pages and sections. Its top-level home object selects which listed Markdown page becomes index.html, the page readers see at the site’s root. docsprout.json.homepage is different: it only controls the presentation of that selected home page.
Edit docs/layout.json. Keep home and unlisted at the top level and add pages inside the navigation list:
{
"schema_version": 1,
"home": {
"path": "index.md"
},
"unlisted": "exclude",
"navigation": [
{
"title": "Get started",
"pages": [
{"title": "Overview", "path": "index.md"},
{"title": "Quick start", "path": "quick-start.md"}
]
},
{
"title": "Reference",
"pages": [
{"title": "Commands", "path": "reference/commands.md"}
]
}
]
}
Each default path starts inside docs/. For example, "path": "reference/commands.md" means the file is docs/reference/commands.md.
For a repository-root README home, keep the matching root navigation page and replace only the top-level home object with:
"home": {
"path": "README.md",
"source": "root"
}
"source": "root" is required only for the exact repository-root README.md. Existing layouts that omit home retain the compatible inference: root README, then docs/index.md, then the first listed page. New layouts should make the selection explicit.
unlisted controls what happens to Markdown under docs/ that is not in navigation:
"error"is the default and preserves existing strict validation. An unlisted Markdown file is reported bydocsprout check."exclude"publishes only listed pages.checksucceeds and reports the number of unlisted documents excluded from the site.
New layouts made by docsprout init use "exclude". Existing layouts are never rewritten; add the field only when you want this explicit publication policy. There are no include/exclude patterns: the navigation list is the complete publication decision.
Authoring navigation in layout.md
You can replace docs/layout.json with a small Markdown outline. Keep exactly one of those two files; DocSprout reports an error if both exist. init still creates JSON for new projects and leaves either existing layout untouched. To switch formats, write docs/layout.md, move layout.json out of docs/, then run docsprout check before discarding the old file.
Layout-Version: 1
Home: index.md
Unlisted: exclude
# Start here
- [Overview](index.md)
## Quickstart {expanded=true}
- [Your first site](beginners-guide.md)
- [Build and inspect](building.md)
# Reference
- [Configuration](configuration.md)
# headings are always visible section labels. ## headings create groups that readers can fold. A group starts closed unless its page is active. Add {expanded=true} to keep it open on every page; {expanded=false} or no attribute keeps the default. The short form {expanded} also means true. Attributes belong only on group headings. Indent group pages by two spaces; leave pages directly under a section unindented. This lets a section page follow a group without changing its position. Links list page titles, paths and order.
Layout-Version: 1 is required. Home: selects a listed page; if omitted, DocSprout uses the same home inference as JSON. Unlisted: accepts exclude or error and defaults to error. For the repository-root README, use ../README.md in both Home: and its page link. This exact target is the only allowed parent path. layout.md itself is configuration and never a page.
Use one page link per line. Paths with spaces can use angle brackets, such as - [First steps](<first steps.md>). In titles and bare paths, prefix literal brackets, parentheses or a backslash with \. Other indentation, deeper headings, freeform Markdown and extra attributes are unsupported. The parser reports malformed lines with their file and line number. The regular JSON layout remains supported and uses the same navigation validation. A complete small project lives at examples/markdown-layout/ in the source repository.
Editing layout.json directly
Every common navigation change is an ordinary edit to docs/layout.json. There are no DocSprout commands for these operations:
| What you want | What you edit |
|---|---|
| Add a page | Add a page object to a section’s pages list |
| Remove a page | Remove its page object |
| Rename a displayed title | Change that page object’s "title" |
| Reorder pages | Move page objects within a pages list |
| Move a page to another section | Cut its object and paste it into another section’s pages list |
| Add a section | Add a {"title": ..., "pages": [...]} object to navigation |
| Rename a section | Change that section’s "title" |
| Add a collapsible group | Add a {"title": ..., "pages": [...]} object inside a section’s pages list |
| Move a page into a group | Cut its page object and paste it into the group’s pages list |
| Keep a group expanded | Add "expanded": true to that group object (default false) |
| Change the home page | Change the top-level "home" object (its path must stay a listed page) |
| Publish or unpublish a page | Add or remove its page object under "unlisted": "exclude" |
Keep each page object on one line, as in the example above. This makes a long navigation list easier to scan and move. docsprout init now writes new layouts this way; it does not reformat an existing layout.
Sections are static headers and always visible. Groups inside a section are collapsible: by default only the group containing the current page starts expanded; every other group starts collapsed but stays one click away. Add "expanded": true to a group to keep it expanded on every page as well. The active group is always expanded so the current page stays visible:
{
"title": "Get started",
"pages": [
{"title": "Overview", "path": "index.md"},
{
"title": "Quickstart",
"expanded": true,
"pages": [
{"title": "Your first site", "path": "beginners-guide.md"}
]
}
]
}
A navigation entry uses either "path" (a page) or "pages" (a collapsible group with child page entries), never both. Groups hold only one level of pages. Omit expanded or use false to keep the default collapsed-unless-active behaviour. It must be a boolean when present. A legacy "expanded" flag on a section object still loads but has no visual effect, since sections are always shown.
The "title" is independent of the filename: a file named install-guide.md can display as Getting installed. The navigation order is the written order of the objects. That is the complete model—there is no hidden state and no second navigation representation. The example above shows the complete file.
DocSprout reports configuration problems precisely. A field that was never part of a released schema-1 configuration is rejected with the file, the exact field path and—when a close match exists—a Did you mean suggestion. For example "theme": {"presett": "purple"} fails with Unknown field 'theme.presett'. Did you mean 'theme.preset'?. Valid configuration from every supported 0.x release keeps loading.
Existing repositories and root README
On its first run, docsprout init considers only README.md at the repository root and Markdown under docs/. It does not modify either one. Ancillary root files such as CHANGELOG.md and CONTRIBUTING.md are deliberately excluded; detection is not permission to publish.
The generated layout uses this narrow navigation entry for a root README:
{"title": "Overview", "path": "README.md", "source": "root"}
"source": "root" supports only the exact repository-root README.md; it does not permit ../README.md, another root file, or any path outside the repository. A README can link to a configured docs/ page and a docs page can link back to the README. Historical builds read the README from the matching Git release archive. Only the repository-root README.md has special root-source support. Other Markdown you want to publish should live under docs/.
After layout.json exists it is authoritative. DocSprout will not discover new pages, alter order or titles, add ancillary files, or reorganise sections. Add an ancillary page only by deliberately listing an allowed docs-path in the layout (for example, after copying or authoring a public docs version yourself).
Reading width
Add layout inside docs/docsprout.json when the default width does not suit the content:
{
"schema_version": 1,
"project": {"name": "MyLibrary-FP"},
"layout": {
"content_width": "wide"
}
}
Choose:
compactfor short, prose-led tutorials;comfortablefor the balanced default;widefor large tables and code samples.
Omit this setting to keep comfortable. The maintained minimal example uses compact, this DocSprout site uses the omitted comfortable default, and the visual fixture uses wide for tables and code.
Footer links
You can add a short footer and a few useful links inside docs/docsprout.json:
{
"schema_version": 1,
"project": {"name": "MyLibrary-FP"},
"identity": {
"footer": "Built for Free Pascal maintainers.",
"links": [
{"label": "Source code", "url": "https://github.com/example/library"}
]
}
}
Link URLs must begin with https:// or http://. DocSprout safely escapes the visible text. The DocSprout site itself is the maintained example: its footer text and Project link appear together at the bottom of every generated page.
Home-page presentation
The default home page works without extra configuration. When you want to change that page’s cards or visible sections, add a homepage object to docs/docsprout.json:
{
"schema_version": 1,
"project": {"name": "MyLibrary-FP"},
"homepage": {
"capabilities": [
{"title": "Offline", "description": "Every asset ships locally."},
{"title": "Stable API", "description": "Guides follow each release."}
],
"sections": {
"release_context": true
}
}
}
Each card needs a non-empty title and description. An empty capabilities list hides all cards. The optional section names are capabilities, banner, introduction and release_context, and each accepts true or false. Omitted section names use these defaults:
| Section | Default | Effect on the selected home page |
|---|---|---|
capabilities | true | Shows the configured cards, or the four standard cards when homepage.capabilities is omitted. |
banner | true | Shows the configured banner image as a full-width band at the top of the home-page hero. It has no effect when no banner is configured. |
introduction | true | Keeps the first paragraph after the H1 heading. |
release_context | false | Shows the release pill inside the home-page hero. |
Start from a complete example in Customize the home page.
Add a home-page banner
A banner is one repository-local image rendered as a full-width band at the top of the home-page hero, above the heading. It never appears on other pages.
- Save the image inside your repository, for example
docs/assets/project-banner.svg. - Reference that file from the top-level
bannerobject:
{
"schema_version": 1,
"project": {"name": "MyLibrary-FP"},
"banner": {
"path": "docs/assets/project-banner.svg",
"alt": "MyLibrary-FP wordmark on a teal field"
}
}
path is repository-relative, must not contain .., and the file must already exist: docsprout build stops with a validation error otherwise. DocSprout copies the image into the built site and renders it at the content width, keeping its proportions and capping it at 10rem tall with object-fit: cover, so wide artwork works best and important details should stay centred. The maintained visual fixture uses a 1200×240 SVG. To keep the setting but hide the image, set homepage.sections.banner to false.
Changing colours, logo and presentation
Appearance and identity are docs/docsprout.json edits:
| What you want | What you edit |
|---|---|
| Change colours | theme.preset, or exact theme.accent / theme.accent_secondary |
| Change the visual style | theme.style (classic, paper, e-ink, glassmorphic) |
| Add a logo | identity.logo (repository-local SVG or PNG) |
| Change the footer | identity.footer and identity.links |
| Add a banner | banner with path and alt |
| Custom CSS (advanced) | theme.custom_css — see Custom CSS |
The documented --dk-* tokens are the stable customisation surface for selectors you write yourself; see Themes.
Customise in this order:
- Colours, visual style, logo, footer and banner — this page and Themes.
- Sections and identity: navigation groups, project attribution and the header mark.
- Customize the home page: cards, introduction and release label.
- Custom CSS: only when the documented options are exhausted.
Release history can wait
Do not add docs/versions.json for a local preview or a single-version site. Add it only when you decide to preserve documentation for older releases. The GitHub Pages guide helps you choose, and the glossary explains terms such as tag, source ref and immutable.