--- atroot: true template: slug: docs title: we rolled our own documentation site subtitle: you don't need mintlify date: 2026-01-12 authors: - name: Akshay email: akshay@tangled.org handle: oppi.li draft: false --- We recently organized our documentation and put it up on https://docs.tangled.org, using just pandoc. For several reasons, using pandoc to roll your own static sites is more than sufficient for small projects. ![docs.tangled.org](/static/img/docs_homepage.png) ## requirements - Lives in [our monorepo](https://tangled.org/tangled.org/core). - No JS: a collection of pages containing just text should not require JS to view! - Searchability: in practice, documentation engines that come bundled with a search-engine have always been lack lustre. I tend to Ctrl+F or use an actual search engine in most scenarios. - Low complexity: building, testing, deploying should be easy. - Easy to style ## evaluating the ecosystem I took the time to evaluate several documentation engine solutions: - [Mintlify](https://www.mintlify.com/): It is quite obvious from their homepage that mintlify is performing an AI pivot for the sake of doing so. - [Docusaurus](https://docusaurus.io/): The generated documentation site is quite nice, but the value of pages being served as a full-blown React SPA is questionable. - [MkDocs](https://www.mkdocs.org/): Works great with JS disabled, however the table of contents needs to be maintained via `mkdocs.yml`, which can be quite tedious. - [MdBook](https://rust-lang.github.io/mdBook/index.html): As above, you need a `SUMMARY.md` file to control the table-of-contents. MkDocs and MdBook are still on my radar however, in case we need a bigger feature set. ## using pandoc [pandoc](https://pandoc.org/) is a wonderfully customizable markup converter. It provides a "chunkedhtml" output format, which is perfect for generating documentation sites. Without any customization, [this](https://pandoc.org/demo/example33/) is the generated output, for this [markdown file input](https://pandoc.org/demo/MANUAL.txt). - You get an autogenerated TOC based on the document layout - Each section is turned into a page of its own Massaging pandoc to work for us was quite straightforward: - I first combined all our individual markdown files into [one big `DOCS.md`](https://tangled.org/tangled.org/core/blob/master/docs/DOCS.md) file. - Modified the [default template](https://github.com/jgm/pandoc-templates/blob/master/default.chunkedhtml) to put the TOC on every page, to form a "sidebar", see [`docs/template.html`](https://tangled.org/tangled.org/core/blob/master/docs/template.html) - Inserted tailwind `prose` classes where necessary, such that markdown content is rendered the same way between `tangled.org` and `docs.tangled.org` Generating the docs is done with one pandoc command: ```bash pandoc docs/DOCS.md \ -o out/ \ -t chunkedhtml \ --variable toc \ --toc-depth=2 \ --css=docs/stylesheet.css \ --chunk-template="%i.html" \ --highlight-style=docs/highlight.theme \ --template=docs/template.html ``` ## avoiding javascript The "sidebar" style table-of-contents needs to be collapsed on mobile displays. Most of the engines I evaluated seem to require JS to collapse and expand the sidebar, with MkDocs being the outlier, it uses a checkbox with the [`:checked`](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:checked) pseudo-class trick to avoid JS. The other ways to do this are: - Use ``: this is definitely a "hack", clicking outside the sidebar does not collapse it. Using Ctrl+F or "Find in page" still works through the details tag though. - Use the new `popover` API: this seems like the perfect fit for a "sidebar" component. The bar at the top includes a button to trigger the popover: ```html ``` And a `fixed` position div includes the TOC itself: ```html
``` The TOC is scrollable independently and can be collapsed by clicking anywhere on the screen outside the sidebar. Searching for content in the page via "Find in page" does not show any results that are present in the popover however. The collapsible TOC is only available on smaller viewports, the TOC is not hidden on larger viewports. ## search There is no native search on the site for now. Taking inspiration from [https://htmx.org](https://htmx.org)'s search bar, our search bar also simply redirects to Google: ```html
...
``` I mentioned earlier that Ctrl+F has typically worked better for me than, say, the search engine provided by Docusaurus. To that end, the same docs have been exported to a ["single page" format](https://docs.tangled.org/single-page.html), by just removing the `chunkedhtml` related options: ```diff pandoc docs/DOCS.md \ -o out/ \ - -t chunkedhtml \ --variable toc \ --toc-depth=2 \ --css=docs/stylesheet.css \ - --chunk-template="%i.html" \ --highlight-style=docs/highlight.theme \ --template=docs/template.html ``` With all the content on a single page, it is trivial to search through the entire site with the browser. If the docs do outgrow this, I will consider other options! ## building and deploying We use [nix](https://nixos.org) and [colmena](https://colmena.cli.rs/) to build and deploy all Tangled services. A nix derivation to [build the documentation](https://tangled.org/tangled.org/core/blob/master/nix/pkgs/docs.nix) site is written very easily with the `runCommandLocal` helper: ```nix runCommandLocal "docs" {} '' . . . ${pandoc}/bin/pandoc ${src}/docs/DOCS.md ... . . . '' ``` The NixOS machine is configured to serve the site [via nginx](https://tangled.org/tangled.org/infra/blob/master/hosts/nixery/services/nginx.nix#L7): ```nix services.nginx = { enable = true; virtualHosts = { "docs.tangled.org" = { root = "${tangled-pkgs.docs}"; locations."/" = { tryFiles = "$uri $uri/ =404"; index = "index.html"; }; }; }; }; ``` And deployed using `colmena`: ```bash nix run nixpkgs#colmena -- apply ``` To update the site, I first run: ```bash nix flake update tangled ``` Which bumps the `tangled` flake input, and thus `tangled-pkgs.docs`. The above `colmena` invocation applies the changes to the machine serving the site. ## notes Going homegrown has made it a lot easier to style the documentation site to match the main site. Unfortunately there are still a few discrepancies between pandoc's markdown rendering and [goldmark's](https://pkg.go.dev/github.com/yuin/goldmark/) markdown rendering (which is what we use in Tangled). We may yet roll our own SSG, [TigerStyle](https://tigerbeetle.com/blog/2025-02-27-why-we-designed-tigerbeetles-docs-from-scratch/)!