maud-ui
58 headless, accessible UI components for Rust web apps. Built on maud + htmx. Styled like shadcn/ui.
- Live gallery: maudui.herman.engineer
- Source:
github.com/hgeldenhuys/maud-ui - Docs: docs.rs/maud-ui
What you get
- 58 primitives — every shadcn/ui component plus some (data-table, resizable, hover-card, OTP input, command palette, calendar, charts).
- Accessible by default — ARIA roles, keyboard navigation, focus management, WCAG-AA contrast in both themes.
- Dark + light themes — flip
data-themeon<html>and the whole tree recolors via CSS variables. - Progressive enhancement — every component renders correctly without JavaScript. JS adds drag, dropdowns, keyboard shortcuts on top.
- Tailwind-compatible — all classes prefixed
mui-, no collisions. Pairing guide → - One Rust dependency — just
maud. No serde, no framework lock-in. Works with axum, actix, rocket, or whatever you use. - Ship pre-built — 46 KB JS + 78 KB CSS minified (11 KB + 11 KB gzipped). No build step required for consumers.
30-second tour
// src/main.rs
use ;
use ;
use ;
async
async
Better yet, clone the repo and run the full component gallery:
# open http://127.0.0.1:3457
The gallery has every component, a live theme toggle, per-component routes with code samples, and a /getting-started page.
Usage
Every component is a module under maud_ui::primitives. Each exposes:
- a
Propsstruct with sensible defaults (viaDefault::default()) - a
render(props) -> Markupfunction - a
showcase() -> Markupfunction used by the gallery (demo only; consumers don't call this)
Example: dialog with a trigger button
use html;
use ;
html!
Example: table with data
use html;
use table;
render
Theming
Flip the theme by setting data-theme on <html>:
<!-- default -->
A theme toggle is included — add <button data-mui="theme-toggle">Toggle theme</button> anywhere and the runtime wires it up.
Custom palette
Override any token in your CSS. Classes are prefixed mui- so nothing collides with your app styles.
}
The full token list is in css/maud-ui.css.
Component reference
Tier 1 — Pure HTML+CSS (works with JS disabled)
Alert • Aspect Ratio • Avatar • Badge • Breadcrumb • Button • Button Group • Card • Chart • Checkbox • Empty State • Field • Fieldset • Input • Kbd • Label • Meter • Native Select • Number Field • Pagination • Progress • Radio • Radio Group • Separator • Skeleton • Spinner • Table • Textarea • Typography
Tier 2 — JS-enhanced (renders without JS; full interactivity with it)
Accordion • Collapsible • Hover Card • Input Group • Input OTP • Switch • Tabs • Toast • Toggle • Toggle Group • Tooltip
Tier 3 — Requires JS for core functionality
Alert Dialog • Calendar • Carousel • Combobox • Command • Context Menu • Data Table • Date Picker • Dialog • Drawer • Menu • Menubar • Navigation Menu • Popover • Resizable • Scroll Area • Select • Slider
Each component's props and variants are documented in its module — run cargo doc --open after adding the crate.
Architecture
src/primitives/ # 58 component modules (Props, Variant, render(), showcase())
src/tokens.rs # Rust constants mirroring CSS custom properties
css/ # Source styles (one file per component + maud-ui.css tokens)
dist/ # Pre-built bundles — serve these to the browser
├─ maud-ui.min.css
├─ maud-ui.min.js
└─ behaviors/*.js
js/build.mjs # esbuild pipeline that concatenates + minifies dist/
examples/showcase.rs # axum server that renders the full gallery
Components are pure functions: (props) -> Markup. No state, no framework. Pair with htmx for interactivity that spans requests, or with vanilla JS for in-page behavior.
Development
# Rebuild dist/ artifacts (requires Node + esbuild)
Tailwind
maud-ui and Tailwind coexist cleanly — see docs/TAILWIND.md for the pairing guide (Preflight, layer order, shared tokens, dark-mode coordination).
License
MIT — see LICENSE.
Credits
Inspired by Base UI (headless primitives), shadcn/ui (visual design), and the WAI-ARIA Authoring Practices.