FontLab theme 2026 · Integration guide
One site. Three libraries.
Keep MaterialX for your documentation. Add FontLab navigation, Basecoat and daisyUI from one shared CDN.
This is a browser asset layer, not a replacement Python theme. ProperDocs builds your Markdown; MaterialX supplies the page, navigation and search; FontLab theme 2026 connects the global menus and adds scoped components.
Download the MaterialX starterBrowse the full component catalogue →
Start a site
Install uv, download starter.zip, and extract it. The archive contains two Markdown pages, a pinned requirements file, a MaterialX configuration and a template override. From its extracted directory:
uv venv --python 3.13
uv pip install -r requirements.txt
uv run properdocs serve -f mkdocs.ymlOpen the preview URL printed by ProperDocs. The sample site_url includes /docs/, so the preview may use that path. Change site_name and site_url before publishing. Then run uv run properdocs build -f mkdocs.yml --strict and publish the contents of site/.
The tested baseline is Python 3.13, ProperDocs 1.6.7, MkDocs 1.6.1 and MaterialX 10.1.8. Consumers need no npm or Tailwind build. The CDN, global menus and external fonts require internet access.
Add it to an existing MaterialX site
Keep theme.name: materialx. Merge the entries below into your existing YAML; do not create duplicate plugins, extra_css or extra_javascript keys. Keep your current navigation, plugins, fonts and template overrides.
This is the complete starter configuration. The first two CSS entries and first two JavaScript entries are the shared layer:
# this_file: examples/starter/mkdocs.yml
site_name: My FontLab documentation
site_url: https://example.org/docs/
docs_dir: docs
site_dir: site
theme:
name: materialx
custom_dir: overrides
features:
- navigation.tabs
- search.highlight
- content.code.copy
palette:
- scheme: default
toggle:
icon: material/brightness-7
name: Switch to dark mode
- scheme: slate
toggle:
icon: material/brightness-4
name: Switch to light mode
plugins:
- search
markdown_extensions:
- attr_list
- md_in_html
- admonition
- pymdownx.superfences
nav:
- Showcase:
- Home: index.md
- Design:
- Next steps: next.md
extra_css:
- https://i.fontlab.com/fltheme26/1.0.0/components.css
- https://i.fontlab.com/fltheme26/1.0.0/theme.css
extra_javascript:
- https://i.fontlab.com/fltheme26/1.0.0/basecoat.js
- https://i.fontlab.com/fltheme26/1.0.0/theme.jsLoad components.css before theme.css, and basecoat.js before theme.js. Load them once per page, after broad legacy resets. Deliberate site overrides may follow them. If your toolkit already injects these assets into final HTML, check for duplicates before adding another copy.
| Asset | Responsibility |
|---|---|
components.css | Scoped Basecoat 1.0.2 and prefixed daisyUI 5.7.44 styles. |
theme.css | Shared colours, component sizing, MaterialX adjustments and responsive panel placement. |
basecoat.js | Basecoat component behavior, restricted to component wrappers. |
theme.js | Mode synchronization, menu/search bridge, page shortcuts and component initialization. |
Choose navigation and search independently
On a MaterialX documentation site, the shared layer defaults to the local drawer and local search when those elements exist. The global bar shows one loupe to the left of one hamburger. The local drawer opens on the right; the theme switcher moves to its bottom. Below the MaterialX desktop breakpoint (76.25em), the global branding scrolls away and the compact controls stay at the upper right while either control serves MaterialX.
<!-- Documentation-first site -->
<fontlab-menu mobile-menu="materialx" mobile-search="materialx"></fontlab-menu>
<!-- Webflow-first site with auxiliary MaterialX pages -->
<vexy-menu mobile-menu="global" mobile-search="global"></vexy-menu>Both brands accept either value on either attribute. JavaScript configuration uses mobileMenu and mobileSearch; attributes take precedence. The current FontLab and Vexy main websites explicitly use global controls, including on auxiliary documentation pages.
Despite its name, mobile-search selects search at every width. Local ownership opens the native MaterialX search index in a desktop dialog or full-screen mobile panel. Global ownership uses the brand search. It does not query the local documentation index. Without a usable local target, the global control remains available.
Keep #__drawer, .md-sidebar--primary, #__search and .md-search. Enable the search plugin and publish search/search_index.json. Do not add a second hamburger, loupe or independent sticky header. Escape closes an open local panel and returns focus.
Try the native MaterialX integration fixture: change ownership, narrow the window, scroll, open the drawer and search for “specimen”.
Follow the site’s appearance
Components inherit the host font and active MaterialX colours. The host owns the theme picker and persistence. A wrapper may explicitly choose data-fltheme-mode="light" or data-fltheme-mode="dark". The source maps Basecoat and daisyUI tokens together; daisyUI’s border width is --du-border, while Basecoat’s --border remains a colour.
<div class="fltheme-components" data-fltheme-mode="dark">
<button class="btn">Dark component area</button>
</div>
<script>
// After manually inserting/restoring component containers:
window.FLTheme?.refresh();
</script>ProperDocs/MaterialX instant navigation is handled automatically through document$. Do not load a second Basecoat runtime. Call FLTheme.refresh() after your own DOM replacement.
Use the Marketing / writing-styleguide editorial design
The component bundle alone preserves native MaterialX typography. The optional editorial layer supplies the five branded modes used by Marketing, the writing styleguide and Ornotto. This is a larger design choice; start from a working site template so its theme picker and body classes travel with its CSS.
# Before the shared components.css and theme.css entries:
extra_css:
- https://i.fontlab.com/fltheme26/1.0.0/editorial/marketing-vendor.css
- https://i.fontlab.com/fltheme26/1.0.0/editorial/fontlab-theme.css
- https://i.fontlab.com/fltheme26/1.0.0/editorial/fontlab-materialx.css
- https://i.fontlab.com/fltheme26/1.0.0/editorial/fontlab-layout.css
# Also load the editorial theme controller:
extra_javascript:
- https://i.fontlab.com/fltheme26/1.0.0/editorial/fontlab-theme.jsMerge these lists with the four shared assets; the fragment is not a complete configuration. Inspect the Marketing sources or Ornotto sources for the companion markup. marketing-vendor.css supports legacy unprefixed content; new components should still use the scoped bundle. The small styleguide.css variant is specific to the writing guide.
Use it in static or Webflow pages
Load the same assets in the final HTML, after existing broad styles. This example adds the FontLab global menu and footer without a MaterialX drawer:
<link rel="stylesheet" href="https://i.fontlab.com/fltheme26/1.0.0/components.css">
<link rel="stylesheet" href="https://i.fontlab.com/fltheme26/1.0.0/theme.css">
<script src="https://i.fontlab.com/fltheme26/1.0.0/basecoat.js" defer></script>
<script src="https://i.fontlab.com/fltheme26/1.0.0/theme.js" defer></script>
<script src="https://i.fontlab.com/menu/fontlab.js" defer></script>
<fontlab-menu mobile-menu="global" mobile-search="global"></fontlab-menu>
<main>
<div class="fltheme-components"><button class="btn">Continue</button></div>
</main>
<fontlab-footer></fontlab-footer>Plain Webflow pages retain their global controls. In fontlab-www-toolkit builds, Markdown is built first, Webflow and static pages are overlaid, then shared assets are injected into final HTML. Check public/, not only the intermediate build_docs/. Preserve cached Webflow content when rebuilding with --skip_webflow.
Navigate with the keyboard
| Key | While reading a documentation page |
|---|---|
| Right or Alt+Right | Next page in navigation. |
| Alt+Left | Previous page in navigation. |
| Left | Previous page in browser history. |
Generated rel="next"/rel="prev" links take priority; primary navigation is the fallback. There is no wraparound at either end. Inputs, editable text, widgets, open dialogs, selected text and other modifier combinations keep their normal behavior. Repeated keydown events do not repeatedly navigate.
Standalone HTML can opt in with data-fl-page-navigation on the body and next/previous links in the head. This guide opts in; ordinary Webflow pages do not.
Check the integration
- Open browser Network tools. Confirm all four shared assets load once, with CSS before their overrides and Basecoat before the theme runtime.
- Inspect a button: its ancestor must be
.fltheme-components. A daisyUI class such asbtn-primarymust becomedu-btn-primary. - If Markdown attributes print literally, enable
attr_list. If Markdown inside a div is literal, enablemd_in_htmland addmarkdown="1". - If local menu/search is missing, preserve the native MaterialX header via
{{ super() }}, enable search, and check the four required native selectors. Check your ownership attributes before changing CSS. - If search opens but finds nothing, serve through HTTP, wait for its index to initialize, and check that
search/search_index.jsonis published at the correct subpath. - If an old look persists, check the final HTML after Webflow/static overlays. Remove duplicate bundles, verify the public asset against the release manifest, then reload cached assets.
- At a narrow width, scroll the global bar out of view. Open and close local navigation and search, check the right-hand drawer, then widen the window and confirm desktop controls and palette placement.
Local previews can retain unrelated browser-console problems from a host site. Record those separately from failures in the shared assets; do not hide them or infer success from a screenshot alone.
Build, update and publish
To consume the theme, publish the output of your normal site build. To change the shared theme itself, work in fontlab-www-docstheme:
npm ci
npm run build
npm test
npm run test:browser
npm run deployThe build needs Node, npm, uv and Python; browser tests need Playwright Chromium (npx playwright install chromium). npm run deploy only stages and hash-verifies dist/ into the sibling img/docs/fltheme26/. Commit and push the CDN repository, wait for Pages success, purge changed URLs if needed, and verify the public files. It does not deploy consumer sites.
Edit src/ for behavior and styles, examples/ for this guide, and fixtures/materialx/ for the native integration fixture. Never edit generated CDN CSS as a source change. manifest.json contains SHA-256 hashes and sizes; 1.0.0/licenses/ retains upstream licences.
The 1.0.0/ path currently receives compatible fixes in place; it is not an immutable release snapshot. Consumers get those changes without a Markdown rebuild once caches refresh. Pin a downloaded asset set if you need an immutable deployment.
See the change history, consumer inventory and published manifest. The latest shared work covers responsive menu/search ownership, Ornotto’s branded layout, page shortcuts, component harmony, equal-sized buttons, opaque Vexy mobile search and final-paragraph spacing.
Basecoat
<div class="fltheme-components">
<button class="btn">Save project</button>
</div>
daisyUI
- Draw
- Space
- Export