• Scholarly
  • Creative
  • Natural
  • Precision
  • Collective

Site-level Configuration Reference

This page documents every setting Tapestry reads from the [extra] table of your site's config.toml, as defined in the theme's own theme.toml. For Zola's own built-in configuration keys (base_url, title, [markdown], taxonomies, and so on), see Standard Zola configuration at the bottom of this page.

Identity & branding

header_logo, header_title, and the brand-mark fallback

[extra]
header_title = "My Research Site"
# header_logo = "images/logo/logo.svg"

The header renders exactly one of the following, in this priority order:

  1. header_logo — an image (including SVG), if set.
  2. header_title — plain text, if header_logo is unset.
  3. Tapestry's own brand mark — an inlined SVG, used only when neither of the above is set. config.title is still included as screen-reader-only text alongside the mark.

Setting header_logo always takes priority — header_title is ignored entirely once a logo image is present.

favicon and favicon_emoji

[extra]
favicon = "images/logo/logo-01-woven-monogram-square.svg"
# favicon_emoji = "🔬"

These are mutually exclusive: if favicon is set, it is used and favicon_emoji is ignored outright, regardless of whether favicon_emoji is also set.

[extra]
copyright = "© $YEAR $AUTHOR :: Powered by [Zola](https://www.getzola.org) :: [Tapestry](https://github.com/anirbanbasu/tapestry) theme."

Presentation style

presentation_style and presentation_variant

[extra]
presentation_style = "scholarly"
presentation_variant = "contemporary-research-lab"

Tapestry ships 5 preset style groups, each with 5 fully-specified variants (25 combinations total). If presentation_style is unset or names a group that doesn't exist, Tapestry falls back to scholarly. If presentation_variant is unset or names a variant that doesn't exist within the selected group, Tapestry falls back to that group's own default variant.

GroupDefault variantAll variants
scholarlycontemporary-research-lab (also the theme-wide default)classic-ivy, nordic-minimalist, dark-academia, scientific-journal, contemporary-research-lab
creativeeditorial-zinebauhaus-studio, editorial-zine, watercolor-atelier, neon-studio, collage-mixed-media
naturalperiodic-table-chemistrycelestial-observatory, periodic-table-chemistry, field-notebook, chalkboard-proof, quantum-circuit
precisionswiss-precision-instrumentblueprint-drafting, surgical-precision, aerospace-materials-lab, biomedical-diagnostics, swiss-precision-instrument
collectivecartographers-atlascartographers-atlas, ledger-index, social-network-diagram, agora-classical-philosophy, strata-geology

Every group and variant independently meets WCAG AA contrast, ships its own self-hosted font pairing, and is built on the same 12-column responsive grid and no-JS navigation collapse.

presentation_style_switcher

[extra]
presentation_style_switcher = true

Opt-in (default false). Adds a disclosure menu next to the theme switcher that lets a visitor preview any group/variant combination live, without a page reload — a two-level accordion (one entry per group, expandable to reveal that group's variants), not a flat list of all 25 combinations. This is one of Tapestry's three sanctioned JavaScript exceptions; with JS disabled, the control simply doesn't appear and the site stays on its build-time presentation_style/presentation_variant.


[extra]
main_menu = [
    { name = "docs", url = "docs", trailing_slash = true },
    { name = "about", url = "about", trailing_slash = false },
    { name = "repo github", url = "https://github.com/anirbanbasu/tapestry", new_tab = true },
]

Each entry supports:

FieldRequiredDefaultNotes
nameyesLink text.
urlyesInternal content path, or a full external URL.
trailing_slashnofalseOnly applies to internal paths (see below).
new_tabnofalseAdds target="_blank".

A url is treated as external whenever it starts with the literal characters http — otherwise it's resolved internally with Zola's get_url(), honouring trailing_slash. new_tab only adds target="_blank"; it does not add rel="noopener" (modern browsers apply that protection to target="_blank" links automatically, but it's worth knowing this isn't set explicitly).

socials

[extra]
socials = [
    { name = "email", url = "mailto:hello@example.com" },
    { name = "github", url = "https://github.com/anirbanbasu" },
    { name = "orcid", url = "https://orcid.org/0000-0000-0000-0000" },
]

Each entry is just name and url — there is no separate icon override key. name must exactly match an SVG filename (without extension) under themes/tapestry/static/images/social_icons/, since it's used directly to build the icon path. A name with no matching file doesn't fail the build — it silently renders a broken icon link, so double-check the spelling against the list below.

Icons currently shipped: bitcoin, bluesky, codeberg, codepen, discord, discourse, email, ethereum, facebook, fediverse, flickr, forgejo, gitea, github, gitlab, google-maps, google-scholar, instagram, keybase, keyoxide, ko-fi, linkedin, mastodon, matrix, monero, orcid, patreon, phone, pixelfed, reddit, researchgate, signal, slack, spotify, stackexchange, stackoverflow, steam, telegram, twitch, venmo, vimeo, whatsapp, x, youtube, zulip (plus atom/rss, normally reserved for feed_icon below).

feed_icon

[extra]
feed_icon = true
# feed_icon = "atom"

Shown in the footer alongside socials, only when config.generate_feeds is also true.


Content features

katex

[extra]
katex = false
# per-page front matter override
[extra]
katex = true

Site-wide default for client-side KaTeX math rendering (one of Tapestry's three sanctioned JS exceptions). Resolved with page-level precedence: a page's own extra.katex, then its section's, then walking up any ancestor sections' extra.katex, then the site-wide config.extra.katex, defaulting to false. An explicit false at a more specific level always wins over a true set higher up — so a section can enable KaTeX globally while an individual page opts back out. With JS disabled, KaTeX-enabled pages show raw, unrendered $...$/$$...$$ source instead of typeset math.

show_default_author

[extra]
show_default_author = true

When true, pages without their own authors = [...] front matter show config.author instead. Set false to only show authorship where a page explicitly declares one.

fediverse_creator

[extra]
fediverse_creator = "@user@mastodon.social"

Emits a <meta name="fediverse:creator"> tag for Mastodon's article attribution feature. Leave unset to omit the tag.


Layout

layout

[extra]
layout = "center"

One of "center", "left", or "full-width", applied as a layout-* body class and used to vary the sizes attribute the responsive_image shortcode generates.


Styling extensibility

stylesheets

[extra]
stylesheets = ["css/custom.css"]

Site-, section-, and page-level stylesheets are all additive — every stylesheet declared at any of the three levels is linked on the resulting page, not just the most specific one. Use this to layer small overrides on top of your chosen presentation style rather than to replace it.


Images

[extra.responsive_images]

[extra.responsive_images]
widths = [640, 784, 1280, 1920, 2560]
fallback_width = 1280

widths is the set of candidate image widths generated for the responsive_image shortcode's srcset; fallback_width is the size used for browsers that ignore srcset. This setting is scoped only to images inserted via that shortcode in your Markdown content — it does not affect og:image (always generated at a fixed 1200×675), the favicon's apple-touch-icon (always 180×180), or header_logo (used at its native size, unresized).


Security

[extra.content_security_policy]

[extra.content_security_policy]
enable = true
allowed_domains = [
    { directive = "base-uri", domains = ["'self'"] },
    { directive = "form-action", domains = ["'self'"] },
    { directive = "img-src", domains = ["'self'", "https://images.example.com"] },
]

Under zola serve, the policy is additionally relaxed with connect-src 'self' ws: and script-src-elem 'self' 'unsafe-inline', to allow the dev-mode live-reload WebSocket. This relaxation never applies to production builds.


Multi-site deployments

site_id

[extra]
site_id = "my-site-slug"

Both the theme switcher and the presentation-style switcher persist a visitor's choice to localStorage, scoped by the browser to the page's origin (scheme+host+port) but not by path. Two Tapestry sites sharing an origin but deployed under different paths — e.g. two GitHub Pages project sites both under username.github.io/ — would otherwise silently share and overwrite each other's saved preferences. site_id namespaces both storage keys to prevent that.

If unset, it falls back to config.base_url, which is enough to distinguish sites in a plain zola build, but not during zola serve (which rewrites base_url to http://127.0.0.1:<port>/, discarding any path) or a zola build --base-url <url> override that strips or normalises the path. Set site_id explicitly if your site is deployed to a shared-origin subdirectory, or regularly tested locally alongside other Tapestry sites on the same port.


Quick reference

KeyTypeDefaultPurpose
site_idstringconfig.base_urlNamespaces the theme-switcher and style-switcher localStorage keys.
presentation_stylestring"scholarly"Top-level style group.
presentation_variantstringgroup's own defaultVariant within the chosen group.
presentation_style_switcherboolfalseOpt-in live style/variant preview menu. Requires JS.
main_menuarray of tables[]Header navigation entries.
socialsarray of tables[]Footer social/contact links.
feed_iconbool | stringunsetShow a feed icon in the footer alongside socials.
copyrightstring (Markdown)built-in fallback textFooter copyright line.
faviconpathunsetFavicon image (SVG or raster). Wins over favicon_emoji if both set.
favicon_emojistring (emoji)unsetEmoji favicon, ignored if favicon is also set.
header_titlestringconfig.titleHeader text, if no header_logo is set.
header_logopathunsetHeader logo image. Takes priority over header_title.
katexboolfalseSite-wide KaTeX math rendering. Overridable per section/page. Requires JS.
layout"center" | "left" | "full-width""center"Overall content-width treatment.
show_default_authorbooltrueShow config.author on pages without their own authors.
fediverse_creatorstringunsetEmits a fediverse:creator meta tag.
stylesheetsarray of paths[]Extra stylesheets, additive with section/page-level stylesheets.
[extra.content_security_policy]tableSite CSP <meta> tag configuration.
[extra.responsive_images]tableWidth candidates for the responsive_image shortcode.

Standard Zola configuration

Root-level keys like base_url, title, description, theme, compile_sass, generate_feeds, author, taxonomies, build_search_index, and the [markdown]/[markdown.highlighting] tables are standard Zola configuration, not Tapestry-specific — see Zola's own configuration documentation for the full reference.

One Tapestry-relevant note: [markdown.highlighting] style = "class" requires some built-in Zola highlighting theme to be configured (e.g. theme = "monokai"), but every presentation style/variant fully overrides the resulting .z-* token colours itself — the configured theme name only acts as a placeholder to satisfy Zola, not as the actual code-block palette you'll see rendered.