Built-in Themes
Shiroa publishes two site themes as separate Typst packages:
@preview/shiroa-starlight:0.4.0@preview/shiroa-starlight:0.4.0provides a native HTML documentation layout inspired by Astro Starlight.@preview/shiroa-mdbook:0.4.0@preview/shiroa-mdbook:0.4.0provides an mdBook-style layout and the HTML wrapper used by Shiroa’s default dyn-paged output.
Both packages expose one main show rule. The page template passes the complete book.typbook.typ as the first argument and the current chapter body as the second. The theme then reads book metadata, builds the page chrome, and places the chapter in the main content area.
See Rendering Targets and Inputs and Reading Metadata for the helpers used below, or Custom Theme to build a theme without either package.
The initialized templates/page.typtemplates/page.typ makes the choice per compilation target:
#import "@preview/shiroa:0.4.0": is-html-target#let web-theme = if is-html-target(exclude-wrapper: true) { "starlight"} else { "mdbook"}#assert(web-theme == "starlight" or web-theme == "mdbook")
#import "@preview/shiroa:0.4.0": is-html-target#let web-theme = if is-html-target(exclude-wrapper: true) { "starlight"} else { "mdbook"}#assert(web-theme == "starlight" or web-theme == "mdbook")
This selects Starlight for native HTML and mdBook for the HTML wrapper and paged phases. It gives each CLI mode a consistent implementation:
--mode=static-html--mode=static-html: Use Starlight for the native HTML page.--mode=dyn-paged--mode=dyn-paged: Use mdBook forhtml-wrapperhtml-wrapper; its pagedweb-*web-*phases return the Typst chapter body that the wrapper loads.--mode=static-html-dyn-paged--mode=static-html-dyn-paged: Native HTML uses Starlight while Typst frames still use the shared paged styling from the page template.- PDF or editor preview: The theme package returns or preserves the Typst body; page, text, equation, and code styling remains the template’s responsibility.
You can force mdBook for native HTML if you prefer its layout. Do not force Starlight for a dyn-paged build: its web-*web-* phase is not supported.
A chapter imports one project show rule:
#import "template.typ": project#show: project.with(title: "Getting Started")= Getting StartedChapter content.
#import "template.typ": project#show: project.with(title: "Getting Started")= Getting StartedChapter content.
The project show rule passes the current page and the book description to a theme:
#import "@preview/shiroa-mdbook:0.4.0": mdbook#let selected-theme = mdbook#let project( title: "", description: auto, body,) = { show: selected-theme.with( include "book.typ", title: title, description: description, plain-body: body, ) body}
#import "@preview/shiroa-mdbook:0.4.0": mdbook#let selected-theme = mdbook#let project( title: "", description: auto, body,) = { show: selected-theme.with( include "book.typ", title: title, description: description, plain-body: body, ) body}
bodybody is supplied by Typst when projectproject is used as a show rule. Passing it as plain-bodyplain-body lets the theme derive a semantic description before other show rules replace the visible content.
// Compile this example with Typst's HTML target.#import "@preview/shiroa-starlight:0.4.0": starlight
// Compile this example with Typst's HTML target.#import "@preview/shiroa-starlight:0.4.0": starlight
The exported function has the signature starlight(book, body, ...)starlight(book, body, ...); its named parameters are described below.
Starlight is intended for native Typst HTML output. Calling it for a paged web-*web-* or PDF target raises an error. Use the target selector above so editor preview and dyn-paged builds use mdBook.
bookbook(content): The includedbook.typbook.typ. Starlight emits it so<shiroa-book-meta><shiroa-book-meta>is available to the sidebar and header.bodybody(content): The current chapter after the theme’s show rules are installed.
titletitle(strstror content, default""""): Visible page heading and the page part of the HTML<title><title>.descriptiondescription(strstr,autoauto, ornonenone, defaultnonenone): A string is used verbatim;autoautoderives text fromplain-bodyplain-body;nonenoneomits the description meta element.plain-bodyplain-body(content orautoauto, defaultautoauto): Source used whendescriptiondescriptionisautoauto.autoautousesbodybody.meta-titlemeta-title(function): Receives(title, site-title)(title, site-title)and returns the browser title. The default producesPage -- SitePage -- Site, or whichever non-empty title is available.
The site title comes from book-meta.titlebook-meta.title. A missing site title is supported; the page title is then used on its own.
enable-searchenable-search(boolbool, defaulttruetrue): Includes or removes the search box and search-results panel.social-linkssocial-links(function): Receives namedgithubgithubanddiscorddiscordURLs. By default they come frombook-meta.repositorybook-meta.repositoryandbook-meta.discordbook-meta.discord.social-iconssocial-icons(function): Renders the link records produced bysocial-linkssocial-links. Override it to change icons or link markup.right-groupright-group(content ornonenone): Replaces the entire right side of the header.nonenonekeeps social links, theme selection, and the mobile sidebar control. A custom value is responsible for any controls it wants to retain.
extra-assetsextra-assets is an array of rawraw CSS or JavaScript blocks. Starlight embeds them in the HTML head after its own assets.
// Compile this example with Typst's HTML target.#import "@preview/shiroa-starlight:0.4.0": starlight#let extra-css = ```css.site-title { font-style: italic;}```#let project(title: "", body) = { show: starlight.with( include "book.typ", title: title, plain-body: body, extra-assets: (extra-css,), ) body}
// Compile this example with Typst's HTML target.#import "@preview/shiroa-starlight:0.4.0": starlight#let extra-css = ```css.site-title { font-style: italic;}```#let project(title: "", body) = { show: starlight.with( include "book.typ", title: title, plain-body: body, extra-assets: (extra-css,), ) body}
Use raw(lang: "js", ...)raw(lang: "js", ...) for JavaScript. Assets are inserted without sanitizing their source, so only include code controlled by the book project.
// Compile this example with Typst's HTML target.#import "@preview/shiroa:0.4.0": is-html-target#import "@preview/shiroa-starlight:0.4.0": starlight#let project( title: "", description: auto, body,) = { if not is-html-target(exclude-wrapper: true) { return body } show: starlight.with( include "book.typ", title: title, description: description, plain-body: body, enable-search: true, ) body}
// Compile this example with Typst's HTML target.#import "@preview/shiroa:0.4.0": is-html-target#import "@preview/shiroa-starlight:0.4.0": starlight#let project( title: "", description: auto, body,) = { if not is-html-target(exclude-wrapper: true) { return body } show: starlight.with( include "book.typ", title: title, description: description, plain-body: body, enable-search: true, ) body}
In a multi-target project, prefer the shared selector shown later instead of returning early, so the same template also applies paged text styling.
#import "@preview/shiroa-mdbook:0.4.0": mdbook
#import "@preview/shiroa-mdbook:0.4.0": mdbook
The exported function has the signature mdbook(book, body, ...)mdbook(book, body, ...); its named parameters are described below.
mdBook builds HTML chrome for htmlhtml and html-wrapperhtml-wrapper. For paged web-*web-* and PDF targets it returns bodybody, allowing the rest of the page template to render the chapter normally.
bookbook(content): Includedbook.typbook.typ; supplies sidebar, repository, and edit metadata.bodybody(content): Current chapter. Inhtml-wrapperhtml-wrapper, mdBook replaces it withpaged-load-trampoline()paged-load-trampoline()so the browser loads the separately compiled paged artifact.
titletitle(strstror content, default[Shiroa Site][Shiroa Site]): Page title used by the menu and HTML title.descriptiondescription(strstr,autoauto, ornonenone): Same semantics as Starlight.plain-bodyplain-body(content orautoauto): Source for an automatic description.meta-titlemeta-title(function): Combines the page and site titles. Its default has the same behavior as Starlight’s default.
The header reads book-meta.repositorybook-meta.repository and book-meta.repository-editbook-meta.repository-edit:
#import "@preview/shiroa:0.4.0": book-meta#book-meta( repository: "https://github.com/example/my-book", repository-edit: "https://github.com/example/my-book/edit/main/docs/{path}", summary: [],)
#import "@preview/shiroa:0.4.0": book-meta#book-meta( repository: "https://github.com/example/my-book", repository-edit: "https://github.com/example/my-book/edit/main/docs/{path}", summary: [],)
{path}{path} is replaced with x-currentx-current after a leading slash is removed. Set an explicit repository-editrepository-edit template when the source is not stored at the theme’s conventional GitHub path.
extra-assetsextra-assets has the same CSS and JavaScript raw-block format as Starlight:
#import "@preview/shiroa-mdbook:0.4.0": mdbook#let project(title: "", body) = { show: mdbook.with( include "book.typ", title: title, plain-body: body, extra-assets: ( ```css :root { --content-max-width: 72rem; } ```, ), ) body}
#import "@preview/shiroa-mdbook:0.4.0": mdbook#let project(title: "", body) = { show: mdbook.with( include "book.typ", title: title, plain-body: body, extra-assets: ( ```css :root { --content-max-width: 72rem; } ```, ), ) body}
The mdbookmdbook signature currently contains three parameters that are not consumed by its entry-point implementation:
enable-searchenable-searchdoes not toggle the search markup.social-linkssocial-linksis not called.right-groupright-groupdoes not replace the header controls.
They are reserved for theme API alignment. Do not depend on them changing the 0.4.0 output. extra-assetsextra-assets, meta-titlemeta-title, repository metadata, and description handling are implemented.
#import "@preview/shiroa-mdbook:0.4.0": mdbook#let project( title: "", description: auto, body,) = { show: mdbook.with( include "book.typ", title: title, description: description, plain-body: body, ) body}
#import "@preview/shiroa-mdbook:0.4.0": mdbook#let project( title: "", description: auto, body,) = { show: mdbook.with( include "book.typ", title: title, description: description, plain-body: body, ) body}
The following is the minimal selection pattern used by an initialized book. Page dimensions, fonts, markup rules, equations, and code styling can be added around it without changing the theme calls.
#import "@preview/shiroa:0.4.0": ( get-page-width, is-html-target, is-pdf-target, is-web-target,)#let project( title: "", description: auto, body,) = { set page( width: get-page-width(), height: auto, ) if is-pdf-target() or is-web-target() show: if is-html-target(exclude-wrapper: true) { import "@preview/shiroa-starlight:0.4.0": starlight starlight.with( include "book.typ", title: title, description: description, plain-body: body, ) } else { import "@preview/shiroa-mdbook:0.4.0": mdbook mdbook.with( include "book.typ", title: title, description: description, plain-body: body, ) } body}
#import "@preview/shiroa:0.4.0": ( get-page-width, is-html-target, is-pdf-target, is-web-target,)#let project( title: "", description: auto, body,) = { set page( width: get-page-width(), height: auto, ) if is-pdf-target() or is-web-target() show: if is-html-target(exclude-wrapper: true) { import "@preview/shiroa-starlight:0.4.0": starlight starlight.with( include "book.typ", title: title, description: description, plain-body: body, ) } else { import "@preview/shiroa-mdbook:0.4.0": mdbook mdbook.with( include "book.typ", title: title, description: description, plain-body: body, ) } body}
Keep plain-body: bodyplain-body: body even when another show rule will style or replace the visible chapter. It gives both themes a stable source for automatic metadata.