dioxus-docs-kit 0.6.1

Reusable documentation site shell for Dioxus applications
Documentation

dioxus-docs-kit

Reusable documentation site kit for Dioxus applications.

Drop-in layout with sidebar navigation, full-text search, page navigation, OpenAPI API reference pages, mobile drawer, and theme toggle. Built on dioxus-mdx for content rendering.

Quick Start

Add to your Cargo.toml:

[dependencies]
dioxus-docs-kit = "0.5"

1. Build a Registry

The DocsRegistry holds all parsed content, the navigation tree, the search index, and any OpenAPI specs:

use dioxus_docs_kit::{DocsConfig, DocsRegistry};
use std::sync::LazyLock;

static DOCS: LazyLock<DocsRegistry> = LazyLock::new(|| {
    DocsConfig::new(
        include_str!("../docs/_nav.json"),
        doc_content_map(), // HashMap<&'static str, &'static str> generated by build.rs
    )
    .with_openapi("api-reference", include_str!("../docs/api-reference/spec.yaml"))
    .build()
});

2. Wire Into Your Router

Create a thin layout wrapper that provides the DocsContext and registry to the library components. The use_docs_providers hook bundles all the context setup into one call:

use dioxus::prelude::*;
use dioxus_docs_kit::{DocsLayout, use_docs_context, use_docs_providers};

#[component]
fn MyDocsLayout() -> Element {
    let nav = use_navigator();
    let route = use_route::<Route>();

    // A plain String — extract the slug from your route, e.g. slug.join("/").
    let current_path = /* ... */;

    // `use_docs_context` rewraps the path reactively for you. Building the
    // signal yourself with a plain `use_memo(move || ...)` captures the first
    // route and never updates — the sidebar highlight would freeze.
    let docs_ctx = use_docs_context(
        current_path,
        "/docs",
        Callback::new(move |path: String| {
            nav.push(/* build route from path */);
        }),
    )
    .with_site_url("https://your-site.com"); // optional: canonical/OG URLs

    let providers = use_docs_providers(&DOCS, docs_ctx);
    // providers.search_open / providers.drawer_open are available for
    // wiring a custom header.

    rsx! {
        DocsLayout {
            Outlet::<Route> {}
        }
    }
}

3. Add Routes

#[derive(Routable, Clone, PartialEq)]
enum Route {
    #[layout(MyDocsLayout)]
        #[route("/docs")]
        DocsIndex {},
        #[route("/docs/:..slug")]
        DocsPage { slug: Vec<String> },
}

That's it. The library handles sidebar rendering, search, page content, previous/next navigation, and mobile responsiveness.

Components

Component Description
DocsLayout Full page layout with sidebar, content area, and table of contents
DocsSidebar Navigation sidebar built from _nav.json
DocsPageContent Renders MDX docs or OpenAPI endpoint pages
DocsPageNav Previous/next page navigation
SearchModal Full-text search across all docs
SearchButton Trigger button for the search modal
MobileDrawer Mobile navigation drawer
ThemeToggle Light/dark theme switcher

Navigation Config

Define your docs structure in _nav.json. tabs is a flat list of tab names, and each group optionally names the tab it belongs to:

{
  "tabs": ["Docs", "Guides"],
  "groups": [
    {
      "group": "Getting Started",
      "tab": "Docs",
      "pages": [
        "getting-started/introduction",
        "getting-started/quickstart"
      ]
    }
  ]
}

Content Pipeline

All doc content is embedded at compile time via include_str!(). A typical build.rs reads _nav.json, collects all referenced .mdx files, and generates a HashMap<&'static str, &'static str> mapping paths to content.

See the example project for a complete build.rs implementation.

Styling Setup

Zero-setup: the precompiled stylesheet

The crate ships a compiled stylesheet (DOCS_KIT_CSS) covering every class its components emit — Tailwind utilities, DaisyUI dark/light themes, typography prose, and the --dk-* theming tokens. Link it and skip the rest of this section — no Tailwind, no Bun, no safelist:

rsx! {
    document::Stylesheet { href: dioxus_docs_kit::DOCS_KIT_CSS }
}

It only contains the kit's classes; if your own pages use Tailwind utilities the kit doesn't, run your own build instead. That path requires Tailwind CSS 4, DaisyUI 5, and @tailwindcss/typography:

Install dependencies

bun add tailwindcss @tailwindcss/typography daisyui

Configure Tailwind

Add to your tailwind.css:

@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "daisyui" {
    themes: dark --default, light;
}

@source "./src/**/*.{rs,html,css}";

Include dioxus-docs-kit classes

When using as a crates.io dependency, Tailwind can't scan the crate source (it lives in ~/.cargo with machine-specific paths). Copy safelist.html from the crate into your project root and add it as a source:

@source "./safelist.html";

The safelist includes all classes from both dioxus-docs-kit and dioxus-mdx, including dynamic runtime classes that Tailwind cannot detect from source scanning alone.

When using as a workspace path dependency, you can point directly at the source instead:

@source "./crates/dioxus-docs-kit/src/**/*.rs";
@source "./crates/dioxus-mdx/src/**/*.rs";

Theming

The kit exposes a public theming surface so consumers can restyle without forking or fighting DaisyUI internals.

Public CSS variables

Copy theme.css from the crate into your project and import it alongside Tailwind:

@import "tailwindcss";
@import "./theme.css";

All tokens have DaisyUI fallbacks, so DaisyUI users inherit the current theme; non-DaisyUI users get a sensible neutral default. Override any of them:

.my-site .dk-root {
  --dk-accent: #f0a57c;
  --dk-font-heading: 'Instrument Serif', serif;
  --dk-radius-lg: 20px;
}
Token Purpose
--dk-bg, --dk-bg-sub, --dk-bg-alt Surface colors
--dk-fg, --dk-muted, --dk-dim Foreground / text colors
--dk-border Border color
--dk-accent, --dk-accent-fg, --dk-accent-soft Accent
--dk-radius-sm, --dk-radius, --dk-radius-lg Corner radii
--dk-font-body, --dk-font-heading, --dk-font-mono Typography
--dk-article-width, --dk-sidebar-width, --dk-toc-width Layout widths

Stable dk-* classes

Structural nodes carry semver-stable dk-* class names. Target these in your own CSS instead of DaisyUI or internal classes:

Class What it wraps
dk-root, dk-docs-root Outermost docs wrapper
dk-header, dk-shell, dk-sidebar, dk-main, dk-toc Layout regions
dk-tabs, dk-tab, dk-tab-active Tab bar
dk-nav, dk-nav-group, dk-nav-group-title, dk-nav-item, dk-nav-item-active Sidebar navigation
dk-article, dk-article-header, dk-article-title, dk-article-description, dk-article-body Article regions
dk-pagination, dk-page-prev, dk-page-next Previous/next links
dk-search-trigger, dk-search-dialog, dk-search-input, dk-search-results, dk-search-result Search
dk-drawer Mobile drawer

Slots on DocsLayout

DocsLayout accepts optional element slots. Each slot is wrapped in a dk-*-slot class for CSS hooks.

DocsLayout {
    announcement_bar: Some(rsx!{ AnnouncementBar {} }),
    sidebar_header: Some(rsx!{ MyProductSwitcher {} }),
    sidebar_footer: Some(rsx!{ EditOnGitHub {} }),
    footer: Some(rsx!{ SiteFooter {} }),
    Outlet::<Route> {}
}

DocsPageContent additionally accepts an article_footer slot (rendered below the article body, before pagination) — useful for "Was this helpful?" widgets.

Density variants

DocsLayout accepts a variant prop for two built-in density presets:

DocsLayout { variant: DocsVariant::Reference, Outlet::<Route> {} }
Variant Feel --dk-article-width
Prose (default) Wide margins, serif-friendly, long-form reading 72ch
Reference Tighter column, smaller type, denser headings 64ch

The variant is emitted as a class on dk-root (dk-variant-prose or dk-variant-reference) so consumers can layer further tweaks.

Pre-built theme examples

examples/themes/ ships three drop-in visual identities built entirely on top of --dk-* tokens:

  • warm-editorial.css — amber accent, serif headings, cream surfaces
  • brutalist-light.css — high contrast, zero-radius, monospace
  • default.css — baseline (nothing overridden)

See THEMING.md for the full roadmap and proposals open for community contribution.

Features

  • web (default) — enables web-specific features (propagated to dioxus-mdx)
  • mermaid (default) — renders ```mermaid fences as diagrams
  • highlight (default) — syntax-highlights code blocks via dioxus-code. Disable (default-features = false) to drop the dependency and its C-compiling tree-sitter grammars: no C toolchain (or wasm stderr shim) is needed and the binary is smaller, but code blocks render as plain (uncolored) text. Turning it off also removes the dioxus-code re-exports and DocsConfig::with_code_theme[s].
  • server — Axum route builders for crawler-facing endpoints

With the server feature, SeoRouter generates per-page raw-Markdown routes, llms.txt / llms-full.txt, sitemaps, blog RSS, and robots.txt as plain Axum routes (server functions would JSON-encode the bodies):

use dioxus_docs_kit::server::SeoRouter;

dioxus::server::serve(|| async {
    let seo = SeoRouter::new("https://your-site.com", "My Docs", "Documentation")
        .with_docs(&DOCS, "/docs")
        .into_router();
    Ok(dioxus::server::router(App).merge(seo))
});

Syntax Highlighting

Code blocks render through dioxus-code. The kit ships highlighting for a common set of languages out of the box:

bash, c#, c++, css, dockerfile, html, javascript, json, markdown, python, rust, toml, tsx, typescript, yaml

To add another language (e.g. Go, Zig, Kotlin), depend on dioxus-code directly with its lang-* feature flag — Cargo unifies it into the kit's transitive dependency, so no kit changes are needed:

[dependencies]
dioxus-docs-kit = "0.5"
dioxus-code = { version = "0.1", default-features = false, features = ["lang-go", "lang-zig"] }

For everything dioxus-code supports in one go:

dioxus-code = { version = "0.1", default-features = false, features = ["all-languages"] }

See the dioxus-code feature list for every available lang-* flag.

License

MIT