Declarative components
Build the UI tree with the view!{} macro: composable, typed components that render the same on the server and, where needed, hydrate on the client.
Qirava Quillqquill
Write components in Rust with view!{}, render them natively on the server, and hydrate only the interactive bits as islands. No server-side JavaScript, no build-tool dependency chain — just a hand-written runtime shipped only where a page actually needs it. This very site is a Quill app.
What it is
Quill is a Rust-native, zero-dependency UI and app framework. You write components in Rust with the view!{} macro; they render to correct, semantic HTML on the server by default, and only the interactive pieces hydrate on the client as islands.
There is no JavaScript toolchain underneath and no server-side JS. The same render path serves a page live and exports it to a static dist/ — the bytes are identical whether served from the engine or from a CDN.
Features
Authoring, components, theming, interactivity, and delivery — one framework, one language, no toolchain to assemble.
Build the UI tree with the view!{} macro: composable, typed components that render the same on the server and, where needed, hydrate on the client.
Headless state machines (qquill-ui) carry the behavior and ARIA contract; styled components (qquill-design) layer token-driven looks on top — use either layer.
Components read --q-* design tokens, so flipping theme, density, or radius restyles the whole app with no reflow and no second stylesheet.
Interactive components hydrate as islands on their trigger. The client runtime is hand-written and imports nothing — it is the entire client footprint, shipped only where used.
One command renders every route in-process and writes a CDN-ready dist/ — HTML per route plus copied assets — that serves with no server running.
quill new myapp lays down a working app: the page list, the render path, and the public assets, ready to cargo run and serve.
How it works
The framework is a small stack of crates that depend strictly inward — products lean on the layers beneath them, never the reverse — so the path from authoring to a shipped page is short and predictable.
A component is a Rust function returning a node tree. view! reads the design tokens and the styled/headless component libraries — view depends on style, theme, and signal; ui and design sit on top.
The tree renders straight to HTML — no client framework boots to show content. Styles compile to one compact CSS string at build time, so there is no runtime styling cost.
An interactive component declares an island: a server-rendered fallback, its sidecar props, and a trigger (load, visible, interaction, or idle). The runtime ships only the behaviors those islands use — pages with none ship zero JS.
The same render path answers a live request or writes a CDN-ready dist/. Because it is one path, the served HTML and the exported HTML are byte-identical.
Architecture
Crates depend strictly inward: authoring sits on the substrate, components sit on authoring, and a page hydrates left-to-right as its islands come alive. Reduced-motion renders the same diagram, static.
Status
Quill is shipping: components, native SSR, islands, motion/3D interactions, and the static export are all in use by this site, which dogfoods the framework end to end.
Read the getting-started guide, browse the component catalog with its live playground, or follow how the islands runtime hydrates in place.