[build.html]

HTML site configuration.

Branding, styling and the quality bar for the site produced by ubc build html. The built-in stylesheet exposes its colours, fonts and metrics as --ubc-* CSS custom properties, which an extra_css file can override.

Guide: HTML site.

build.html.announcement
Type:
string
Default:
""

A site-wide banner shown at the top of every page.

The value is inserted into the page as raw HTML, not escaped, so the banner can carry markup — a link, emphasis — and, equally, a malformed fragment reaches every page as written. The banner is one line tall and does not follow the page as it scrolls: block markup is clipped, and a value too long for the viewport can be scrolled towards its end but not always back to its start, so keep it to one short sentence. It is not hidden when the page is printed, though whether its colours print depends on the browser’s background-graphics setting. Unset or "" means no banner.

build.html.copyright
Type:
string
Default:
""

The site copyright statement.

Shown in each page’s footer as Copyright © {value} — e.g. the value "2026, team useblocks" renders as Copyright © 2026, team useblocks. Pages without the site shell (no sidebar and no page-contents column) have no footer. Unset or "" means no copyright line.

build.html.deny
Type:
string
Default:
"warning"

The lowest severity of finding that fails the build.

ubc build html reports two kinds of finding — render-phase build warnings and indexing diagnostics — and this is the single bar both are held to: any finding at or above this level fails the command with exit code 1. Defaults to warning, so any warning-or-worse finding fails the build; error lets warnings through and fails only on errors, and none never fails. The site is written before the gate is applied either way, so a failing build can still be published for inspection. --deny on the command line overrides this for a single run, and codes silenced under [lint] never reach the gate.

Values:

  • "none": Never fail on findings.

  • "info": Fail on any finding, informational ones included.

  • "warning": Fail on any warning-or-worse finding.

  • "error": Fail only on errors.

build.html.extra_css
Type:
array of strings
Default:
[]

Extra stylesheets to copy into the site and link on every page.

Paths are relative to this ubproject.toml (or absolute). Each file is copied into the site’s _static/ directory and linked AFTER the built-in stylesheet, in the order listed, so a later file wins over an earlier one and any of them wins over the built-in defaults. Two files with the same name are both copied, under distinct names. A file that cannot be read is reported as a build warning and skipped; the rest of the site still builds. Unset or empty means no extra stylesheets.

build.html.extra_static
Type:
array of strings
Default:
[]

Extra files and directories to copy into the site’s _static/ directory.

For the files a stylesheet references — background images, fonts, icons — so that a url(...) in an extra_css sheet resolves beside it. Nothing listed here is linked from the pages.

Paths are relative to this ubproject.toml (or absolute). A listed DIRECTORY has its CONTENTS copied, preserving their structure: with the entry assets, the file assets/img/bg.png lands at _static/img/bg.png. A listed FILE lands flat at _static/{filename}. INSIDE a listed directory, dot-prefixed files and directories are skipped and symlinked directories are not descended into; listing such a path as an entry publishes it, because naming it is consent.

A destination already claimed — by a built-in site asset, by an extra_css / logo / favicon copy, or by an earlier entry — is reported as the build warning build.extra_static_collision and that file is skipped: never renamed, never overwritten, because the destination spelling is what a stylesheet’s url(...) refers to. A file that cannot be read is build.extra_static_read_failed (the rest of the tree still copies), and an entry inside the output directory is build.extra_static_invalid_entry. Names are compared ignoring case, so a collision that would only bite on macOS or Windows is still reported on Linux.

An extra_css sheet that lives inside a listed directory is copied once for that directory, at its structure-preserving destination, and linked there. Entries that OVERLAP (one nested inside another) are each walked from their own root, so content they share is published under both entries’ destinations.

Unset or empty means nothing extra is copied.

build.html.favicon
Type:
string
Default:
""

The site favicon.

An icon file (.ico, .svg, .png, …) shown in the browser tab. The path is relative to this ubproject.toml (or absolute); the file is copied into the site’s _static/ directory and linked from every page. A file that cannot be read is reported as the build.favicon_read_failed warning and skipped. Unset or "" means no favicon.

build.html.footer_icons
Type:
array of tables
Default:
[]

Icon links shown at the right of every page’s footer row.

Written as a list of tables, one per icon, each with four optional string keys: html, the icon markup, which is inserted into the page as raw HTML, not escaped (an inline SVG drawn with currentColor follows the site’s light and dark themes); url, the link target; name, the link’s accessible label, which is what a screen reader announces; and class, extra CSS classes added to the link.

An entry with no url, or with neither html nor class, cannot render as a usable link: it is skipped, and reported as the build warning build.footer_icon_invalid. An entry with no name is still rendered — with no label for assistive technology — and reported under the same code. With every entry skipped, no icons row is emitted.

An extending configuration replaces the whole list rather than adding to it. Unset or empty means no icons.

Each entry: One icon link in the site footer.

build.html.footer_icons[].class
Type:
string
Default:
""

Extra CSS classes for the link, added to the built-in ub-footer-icon.

For an icon supplied by a font shipped through extra_css, and for per-icon styling of your own.

build.html.footer_icons[].html
Type:
string
Default:
""

The icon markup.

Inserted into the page as raw HTML, not escaped. An inline svg drawn with fill="currentColor" or stroke="currentColor" takes the footer’s text colour and so follows both the light and the dark theme; the stylesheet sizes an svg or img here to one line. May be left out when class supplies the icon instead (an icon font).

build.html.footer_icons[].name
Type:
string
Default:
""

The link’s accessible label — what a screen reader announces for it.

An icon has no text of its own, so without this the link is announced with no name at all. Omitting it is reported as the build warning build.footer_icon_invalid, and the link is still shown.

build.html.footer_icons[].url
Type:
string
Default:
""

The link target.

Used as written, so an external link needs its scheme (https://example.com). An entry without one is skipped and reported as the build warning build.footer_icon_invalid.

build.html.hide_attribution
Type:
boolean
Default:
false

Hide the footer’s “Built with ubc” attribution line.

Removes that line and nothing else: the footer, its divider and the copyright line (when set) all stay, and so does each page’s <meta name="generator">. When the footer’s bottom row would then be left with no content at all — no copyright, no footer icons — the row is not drawn, rather than leaving a bare divider behind. Defaults to false.

build.html.hide_title
Type:
boolean
Default:
false

The logo artwork already contains the site name, so the title text is not repeated beside it.

Hides the title wherever the site shell brands the site with the logo (today: the sidebar heading); assistive technology still hears the name (it becomes the logo’s alternative text), and browser titles and the narrow-viewport header keep the text. With no logo configured either, the sidebar shows no heading — including its link to the root page. Defaults to false.

build.html.highlight
Type:
table
Default:
{ aliases = {}, enabled = true }

Syntax-highlighting settings for the site.

The same keys as [build.highlight]. This table inherits every key it does not set from [build.highlight] and wins on every key it does, enabled = false included.

The builders colour the code in a code-block, a literalinclude and a fenced block — and inline code with a language — using the language the code names. The set of languages is a bundled collection of Sublime Text syntax definitions, so it is the same on every machine and needs nothing installed. The colours are the hl-* roles under [build.pdf.theme.colors] on paper, and the --ubc-hl-* custom properties on the site.

These keys can be written once in [build.highlight] for every output format, or in one format’s own table — [build.pdf.highlight], [build.html.highlight] — which inherits every key it does not set from [build.highlight] and wins on every key it does, enabled = false included.

Both ubc build pdf and ubc build html read them, and they colour code with the same engine, so a language name and a decision about colour mean the same thing on paper and on the site.

build.html.highlight.aliases
Type:
table of strings
Default:
{}

Extra names for languages, on top of the built-in table.

Each entry maps a name you write — in a code-block argument, a :language: option or a .. highlight:: — to the language it should be coloured as. The value is another language name ("python", "toml", "rst"), or "text" to draw the code plain and report nothing.

An entry wins over the built-in name of the same spelling, so default = "text" turns off the built-in “an unmarked block is Python” behaviour. Names are matched ignoring case and surrounding spaces, and a value is looked up ONCE: it must name a language directly, not another entry in this table. A value that names no language is reported when the project is read, and under the default --deny warning that stops the build — unless highlighting is off for that format, in which case no name is looked up and nothing is reported.

Written here this applies to every output format. A format’s own table ([build.pdf.highlight], [build.html.highlight]) REPLACES this map for that format rather than adding to it.

Empty by default, in which case only the built-in names resolve.

build.html.highlight.enabled
Type:
boolean
Default:
true

Colour the code in code blocks and in inline code that names a language.

Defaults to true. Setting this to false draws all code in the document’s own code colour — code-fg on paper, the --ubc-code-fg custom property on the site — as the builders did before they could highlight. It does not affect the line-number gutter, and it does not affect the band an :emphasize-lines: option draws behind a line. The colours themselves are the hl-* roles under [build.pdf.theme.colors] on paper, and the --ubc-hl-* custom properties on the site.

build.html.legacy_anchor_redirects
Type:
array of strings
Default:
[]

Keep deep links written against a previous [parse] id_style working.

For every id on a page that a style listed here would have spelled differently, the page gains a redirect from the old spelling to the new one, so a deep link written against an old anchor that nothing on the page carries any more lands on the element that carried it. List the OTHER style: "docutils" on a "github" project (anchors a Sphinx build, or ubCode before "github" became the default, made — #needs-types-2-0 forwards to #needs_types-20), or "github" on a "docutils" project (links written against GitHub- or MyST-style anchors).

An old anchor the page still carries is never redirected: the page’s own anchor always wins, even when the new style gave that string to a DIFFERENT element (a positional #id1 now taken by a footnote, or one title now spelled the way another used to be), and no entry can override it. That is the usual outcome, not a rare one: in ubCode’s own test projects every such anchor lands on a different element, and on its documentation the one case lands on the same section.

Unset or empty — the default — generates no entries. A style that is the project’s own [parse] id_style generates nothing, and says so with the warning config.legacy_anchor_redirects_own_style.

The generated entries join the page’s anchor-redirect map, the one a [build.html.redirects] key naming a section writes to, and a [build.html.redirects] entry for the same anchor wins. The forwarding happens in the reader’s browser: a reader without JavaScript, a crawler and an objects.inv consumer see the new anchors only.

Each entry: How HTML ids are made from section titles and names.

Values:

  • "github": GitHub’s heading-anchor convention (the default).

  • "docutils": Sphinx’s anchors (docutils’ make_id), to keep a Sphinx build’s anchors and existing deep links.

Type:
string
Default:
""

An image file to show above the sidebar heading.

The path is relative to this ubproject.toml (or absolute); the file is copied into the site’s _static/ directory. It is scaled to fit the sidebar width. A file that cannot be read is reported as the build.logo_read_failed warning and skipped. Unset or "" means no logo.

build.html.logo_dark
Type:
string
Default:
""

A dark-theme variant of logo.

Shown instead of logo while the site renders in its dark theme (chosen with the theme toggle, or following the system preference); printing uses logo when both are set. Resolved and copied like logo (an unreadable file is the same build.logo_read_failed warning), and meant to be set together with it — set alone it behaves like logo (used everywhere, including print). Unset or "" means logo (when set) is used in both themes.

build.html.plantuml
Type:
table

Settings for rendering diagrams with an external PlantUML executable.

ubCode can draw the needuml and needarch views, the authored uml / plantuml directives (and their MyST {uml} / {plantuml} fences), and — when needflow / needsequence are set — the needflow and needsequence views, by running a PlantUML executable you install and maintain, instead of converting them to Mermaid. It is off by default, and the live preview always uses the Mermaid conversion.

These keys can be written once in [build.plantuml] for every output format, or in one format’s own table such as [build.html.plantuml], which inherits every key it does not set from [build.plantuml] and wins on every key it does, enabled = false included.

PlantUML 1.2026.2 or newer is required. Older releases accept the command-line options this feature relies on and then ignore them, so the diagram it produced would not be under the controls described here.

ubCode always sets PlantUML’s SANDBOX profile, as a JVM property and in the environment. That is a safe default rather than a guarantee: the executable is yours, and what you put in command can relax it — a later -DPLANTUML_SECURITY_PROFILE=UNSECURE, a wrapper script that re-exports the profile, or an entry that strips the environment. That is your explicit choice: ubCode does not diagnose which of the two PlantUML prefers, and cannot contain what PlantUML then reads.

build.html.plantuml.command
Type:
array of strings
Default:
[]

The PlantUML executable to run, written as a command and its arguments.

Always a list, never a single string. For a JAR give the launcher and the JAR — ["java", "-jar", "/opt/plantuml.jar"] — and put any JVM options (-Xmx512m) before -jar; for a wrapper script or a native build, one entry is enough.

The FIRST entry is the program: a bare name is looked up on PATH, and one containing a path separator is taken relative to this ubproject.toml. Every entry after it is passed through EXACTLY as written.

To point at a file beside this ubproject.toml, write {config_dir} and ubCode replaces it with that directory — anywhere in any entry, as often as you like: ["java", "-jar", "{config_dir}/libs/plantuml.jar"]. Nothing else in an argument is rewritten, so a container image name, a KEY=VALUE pair or a URL reaches your program unchanged.

Required when the renderer is enabled — a command that cannot be run is reported as the build warning build.plantuml_exec_failed, and so is an unset or empty one.

ubCode always runs PlantUML under its SANDBOX profile, and what you write here can relax it: a later -DPLANTUML_SECURITY_PROFILE=UNSECURE argument, or a wrapper script that re-exports the profile before starting PlantUML. That is your explicit choice — ubCode does not diagnose whether PlantUML prefers the property or the environment, cannot contain what PlantUML then reads, and PlantUML’s own allowlist confines neither .. nor symbolic links.

build.html.plantuml.enabled
Type:
boolean
Default:
false

Render PlantUML diagrams with an external PlantUML executable instead of converting them to Mermaid.

Applies to the needuml / needarch views and the authored uml / plantuml directives in the built output, and to the needflow / needsequence views when their own keys are also set. Defaults to false, which leaves each builder to draw the diagram itself — in the HTML site, as the Mermaid conversion. The live preview always uses the Mermaid conversion, so an enabled project’s diagrams can look different in the preview than on the built page. Writing this table without setting this key leaves the renderer off.

build.html.plantuml.min_version
Type:
string
Default:
""

The oldest PlantUML version this project accepts.

Written the way PlantUML writes it, 1.2026.4, and checked once per build against the version the executable reports. Below it the renderer is switched off for that build with the warning build.plantuml_version_unsupported and the diagrams fall back to what the builder draws without the renderer (in the HTML site, the Mermaid conversion).

This can only RAISE the bar: it cannot be set below the built-in minimum of 1.2026.2, and a lower value is reported as the build warning build.plantuml_exec_failed and ignored in favour of that minimum. An executable whose reported version cannot be read at all is reported as build.plantuml_version_unparsed and not used, since there is then no version to check against the minimum.

Diagram appearance can change between PlantUML releases, so upgrading can change how your diagrams look. Unset or "" means 1.2026.2.

build.html.plantuml.needflow
Type:
boolean
Default:
false

Also draw the needflow views with the external PlantUML executable.

Needs enabled as well: this key chooses which diagrams the renderer draws, never whether there is one, so needflow = true on its own changes nothing. Defaults to false in both builders, which draws every needflow the way ubCode draws it today (in the HTML site, as a client-side Mermaid flowchart; in the PDF, as a box showing the diagram source).

This is a FIDELITY setting: the diagram is laid out by PlantUML itself, the way a Sphinx-Needs build with needs_flow_engine = "plantuml" lays it out, and each node becomes a link to its need. Some intents cannot be carried over exactly — :direction: up and :direction: left are drawn on their axis mate, a type style that is not a PlantUML keyword is drawn as a rectangle, and style_start / style_end are ignored.

[needs] flow_engine is the low-precedence default for this key, so a ubproject.toml shared with a Sphinx-Needs build need not say the same thing twice. A diagram’s own :engine: option overrides both, in either direction. The live preview always uses the Mermaid conversion, whatever this says.

build.html.plantuml.needsequence
Type:
boolean
Default:
false

Also draw the needsequence views with the external PlantUML executable.

Needs enabled as well, exactly as needflow does, and defaults to false in both builders. A separate key from needflow because a project may well want its traceability graph drawn by PlantUML and its message diagrams left as they are.

[needs] flow_engine does NOT drive this key. Sphinx-Needs’ own needsequence is PlantUML-only and has no engine option at all, so the key that chooses between engines has nothing to say about this family.

With it off, a needsequence is the Mermaid sequence diagram ubCode draws itself (a box showing that source, in the PDF). With it on, it is laid out by PlantUML. The live preview always uses the Mermaid conversion, whatever this says.

build.html.plantuml.timeout
Type:
integer
Default:
60

How long the whole diagram-rendering step may take, in seconds.

The bound covers the single run that renders every diagram needing an update, not each diagram. Diagrams that produced no output when it expires are reported as the build warning build.plantuml_timeout and fall back to what the builder draws without the renderer (in the HTML site, the Mermaid conversion). Defaults to 60; 0 is refused as build.plantuml_exec_failed.

build.html.redirects
Type:
table of strings
Default:
{}

Redirects from the paths of pages and sections that moved to where they moved to.

Each key is a page — or a section of one — that no longer exists at that address, and each value is what it became, so a reader holding an old link still arrives. ubc build html writes a small forwarding page where the old page used to be, carrying the reader on with the ?query they arrived with (unless the target names one of its own), and with their #fragment too — unless the entry names a section, in which case the entry’s own destination replaces it.

Keys and targets are written the way a toctree entry is: /-separated and relative to the source directory, with a leading / and a source suffix (.rst, .md, …) both optional and both ignored. Either side may name a section ("guide/old#setup" = "guide/new#install"), and a target may instead be an external http:// / https:// URL; any other URL scheme is refused.

A key naming a SECTION works in the reader’s browser, because a fragment never reaches the server: if the key’s page still exists the entry rides that page’s own script, and if the key’s page is itself redirected the entry travels in its forwarding page — a key whose page is neither is refused. A section that is still present always wins, so an entry for an anchor that has not really moved is inert rather than surprising.

Redirect chains are followed to the end, so a reader is forwarded exactly once — including across the two layers, when a page and one of its sections both moved.

Unset — the default — means no redirects and no forwarding pages. Deleting an entry deletes its forwarding page from the output on the next build. A faulty entry is skipped with a build warning rather than stopping the build: build.redirect_invalid (a key or target that cannot be read, or a section key on a page that is neither rendered nor redirected), build.redirect_source_exists (the key names a page that still exists, and that page keeps its own content), build.redirect_target_missing (the target names no page), build.redirect_cycle (entries that redirect in a loop), build.redirect_anchor_unknown (the target page renders no such section) and build.redirect_anchor_shadowed (the key’s section is still there, so the entry can never fire).

build.html.sd_tabs_storage_prefix
Type:
string
Default:
"ubc-tab-id-"

The localStorage key prefix under which a reader’s tab-item selection is remembered.

A tab-item with a :sync: key records the reader’s choice, so that picking (say) a language in one tab set selects it in every other set on the page, and keeps it on the next page and the next visit. Set this to an empty string to switch that off: tabs then still switch and still sync within a page, but nothing is written to browser storage and every page starts on its default tab.

Unset means ubc-tab-id-. The value is delivered to the browser as an attribute on the tab script that a page with tabs links, so it shapes the built site only — the editor preview runs no script and is not affected either way.

Equivalent to sphinx-design’s sd_tabs_storage_prefix configuration value, but NOT sharing its default of sphinx-design-tab-id-: a page built by both tools on one domain would otherwise read and overwrite the other’s stored choices. Set it explicitly on both sides if you want them shared.

build.html.search
Type:
table
Default:
{ enabled = true }

Site search configuration.

The site produced by ubc build html includes a full-text search index over its pages, sections and needs, plus a search box in the sidebar and a search.html results page. Everything is generated at build time and works from a local file:// copy of the site — no server and no network access are needed.

build.html.search.enabled
Type:
boolean
Default:
true

Whether to build the search index and ship the search UI.

Defaults to true. Setting this to false removes the search box, the results page and the index files from the site (a rebuild of an existing site also deletes the ones it wrote before), and skips the indexing work during the build. Turn it off for very large projects where the index file has grown impractical, or where the site is only ever read through a search-capable host.

build.html.source_branch
Type:
string
Default:
""

The branch or tag the source links point at.

Read together with source_repository when building each page’s view/edit URL — typically main or master. It is not consulted by source_view_link / source_edit_link, which carry their own targets, and it does nothing on its own: without a repository there is no URL for it to be part of. Set with neither a repository nor a link template it can reach nothing, and is reported as the build warning build.source_link_invalid — and a repository set with no branch is reported the same way, for whichever button no template covers. Unset or "" means no branch.

build.html.source_directory
Type:
string
Default:
""

The path from the repository root down to this project’s source directory.

Prefixed to each page’s source path when the URL is built from source_repository, so a project whose sources live in docs/ of its repository sets docs/ here. A leading or trailing / is optional.

It applies to the source_repository construction ONLY: a source_view_link / source_edit_link template receives the page path WITHOUT this prefix. Set with neither a repository nor a link template it does nothing, and is reported as the build warning build.source_link_invalid. Unset or "" means the sources sit at the repository root.

Type:
string
Default:
""

A URL template for the “edit this page” button.

The source_view_link twin, with the same {filename} substitution and the same freedom from host checking: it overrides the source_repository construction for the edit button alone, and works on its own. Unset or "" falls back to that construction.

build.html.source_repository
Type:
string
Default:
""

The URL of the repository holding this project’s source files.

Set it together with source_branch and every page written from a source file gains “view this page” and “edit this page” buttons above its content, each linking to that page’s own source. The generated search results page has no source file and so shows neither, and a page with no navigation and no sub-sections shows no page chrome at all.

Three hosts are recognised, and only over https: https://github.com/…, https://gitlab.com/… and https://bitbucket.org/…. A trailing / — or a trailing .git, as a clone URL carries — is optional.

A repository with no source_branch, an http:// URL, or a host outside those three draws no button and is reported as the build warning build.source_link_invalid — for any other forge, use source_view_link / source_edit_link instead, which override this key and are never checked against the host list. Unset or "" means no buttons.

Type:
string
Default:
""

A URL template for the “view this page” button.

Overrides the source_repository construction for this one button, and works on its own with no repository set. Every {filename} in the value is replaced by the page’s source path relative to the project’s source directory, suffix included (guide.rst, topics/intro.md) — source_directory is NOT prefixed to it.

The value is used as written and is not checked, so a template that names a host outside the three recognised ones is fine here. Unset or "" falls back to the source_repository construction.

build.html.title
Type:
string
Default:
""

The site title.

Shown as the sidebar heading and appended to each page’s browser title as page title — site title (a page whose own title already equals it is left unsuffixed). Overrides [project].name, which is used for the sidebar heading when this is unset. Unset or "" leaves page titles unsuffixed.