Skip to content

A demo, in Rust

Interactivity is a CSS feature now.

Five pages of menus, modals, tabs, tooltips, sorting and validation. Rendered by axum and maud, styled with Tailwind, and shipped with exactly zero bytes of JavaScript — no script tags, no hydration, no bundle.

Try the interactive pageRead the source layout0 kB of JS

Navigate between pages

@view-transitionDeclaring @view-transition { navigation: auto } opts the whole document into cross-document view transitions, so the browser cross-fades between two server-rendered pages instead of flashing white.

Step one

Click a nav link

The old page is captured as a snapshot before the request completes.

Step two

Server renders

axum returns a full HTML document. No client router is involved.

Step three

Browser cross-fades

The header keeps its view-transition-name, so it stays put while the body fades.

view-transition-nameThe sticky header is given a stable transition name, which makes the browser treat it as the same element across the navigation rather than fading it out and back in.

Reveal on scroll

animation-timeline: view()Each section runs a fade-and-rise keyframe animation whose timeline is its own position in the viewport, so progress is driven by scrolling rather than by a script watching an IntersectionObserver.

01

The sidebar on the interactive page is a checkbox plus body:has(#toggle:checked).

02

The dropdown and the modal are the popover attribute, styled with :popover-open.

03

The data table sorts and filters in Rust, driven entirely by query parameters.

04

The form validates server-side and renders its own errors back into the markup.

animation-range: entryThe animation range is pinned to the element's entry into the scrollport, so each row finishes its reveal shortly after it clears the bottom edge.

Reading progress

animation-timeline: scroll(root)The bar at the top of this page scales along the X axis with a scroll-progress timeline attached to the document's scroll container — no scroll listener, no layout thrash.

Graceful degradation

Everything here is progressive

Browsers without scroll-driven animations simply show the content in its final state; browsers without @view-transition just navigate normally. Nothing depends on the effect firing.
No polyfillsNo fallback JS

Motion safety

prefers-reduced-motion is respected

All reveals and transitions sit behind a reduced-motion media query, so the site is static for anyone who asks for that.