Interactive UI & animation showcase
A living catalogue of the headless primitives in @remix-run/ui plus its animation helpers, styled by this app. Every preview is a server-rendered, client-hydrated Remix island whose parameters you can change on the fly.
- @remix-run/component
- 1.0.0
- @remix-kbn/ssg
- 0.13.0
- Deno
- 2.9.7
Headless primitives from @remix-run/ui, styled by the app
Each card is built on a headless primitive from @remix-run/ui — behavior and accessibility from the package, styling from this app. Use the controls below each preview to change its parameters live; the previews are hydrated islands.
Toggle
@remix-run/ui/toggleA headless mixin that turns a native checkbox into an accessible switch.
<input type="checkbox" mix={toggle.control({ defaultChecked: true })} />State is native — the switch uses the checkbox's own checked value.
Tabs
@remix-run/ui/tabsA tab control with one active tab and matching panels, controlled or self-managed.
A high-level summary of the project and its current status.
Recent commits, deploys, and comments from your team.
Visibility, access control, and notification preferences.
<tabs.Context activeTab="overview">
Arrow keys move between tabs; Home and End jump to the first and last.
Accordion
@remix-run/ui/accordionA disclosure set with single or multiple expandable items.
Manage profile, email, and password preferences.
Review invoices and update the payment method.
Choose which events send email and in-app alerts.
<accordion.Context defaultValue="account" collapsible={true}>
<accordion.ItemContext value="billing">
<h3><button mix={accordion.trigger()} /></h3>
</accordion.ItemContext>
</accordion.Context>Select
@remix-run/ui/selectA button-triggered popup value picker backed by listbox and popover.
<select.Context name="framework">
<button mix={select.trigger()} />
<popover.Context>
<div mix={select.popover()}>
<div mix={select.list()}>
<div mix={select.option({ value: "remix", label: "Remix" })} />
…
</div>
</div>
</popover.Context>
<input mix={select.hiddenInput()} />
</select.Context>
// value = nullReact Router is a disabled option — keyboard and pointer selection skip it.
Combobox
@remix-run/ui/comboboxAn input-first picker: type to filter aliases, commit one stable value.
<combobox.Context name="airport">
<input mix={combobox.input()} />
<div mix={combobox.popover()}>
<div mix={combobox.list()}>
<div mix={combobox.option({ value: "LAX", label: "Los Angeles International", searchValue: ["lax", "los angeles"] })} />
…
</div>
</div>
<input type="hidden" mix={combobox.hiddenInput()} />
</combobox.Context>
// value = nullTry typing a code like "hnd" or a city like "tokyo" — searchValue aliases match both.
Listbox
@remix-run/ui/listboxThe headless option-list primitive with controlled selection and highlighting.
<listbox.Context value="remix" activeValue="remix" onSelect={…} onHighlight={…}>
<div mix={listbox.list()}>
<div mix={listbox.option({ value: "remix", label: "Remix" })} />
<div mix={listbox.option({ value: "react-router", label: "React Router", disabled: true })} />
…
</div>
</listbox.Context>Selection and highlighting are fully controlled — arrow keys, typeahead, and click all route through onSelect / onHighlight.
Popover
@remix-run/ui/popoverThe low-level anchored, dismissible floating surface primitive.
<popover.Context>
<button mix={[popover.anchor({ placement: "bottom-start", offset: 8 }), popover.focusOnHide()]} />
<div mix={popover.surface({ open, onHide })}>
<button mix={popover.focusOnShow()} />
</div>
</popover.Context>Opening locks page scroll; Escape or an outside click dismisses and restores focus.
Anchor
@remix-run/ui/anchorThe positioning engine that keeps a floating element pinned to an anchor.
<div mix={ref((floating) =>
anchor(floating, target, {
placement: "bottom",
offset: 10,
inset: false,
})
)} />The animation primitives, parameterised
Spring, tween, entrance/exit, and layout helpers from @remix-run/ui/animation. Tune the presets and curves and replay the motion in place.
Spring
animation · springSwiftUI-style spring physics, stringified into a CSS linear() transition.
<div style={{ transition: spring.transition("left", "bouncy") }} />Tween
animation · tweenA generator that interpolates a value over time with a cubic-bezier curve.
let animation = tween({ from: 0, to: 100, duration: 700, curve: easings.easeOut })
requestAnimationFrame(function tick(t) {
let { value, done } = animation.next(t)
bar.style.width = `${value}%`
if (!done) requestAnimationFrame(tick)
})Entrance & exit
animation · animateEntrance / animateExitAnimate keyed elements as they are inserted into and removed from the DOM.
- Design review
- Ship release
- Write changelog
<li mix={[
animateEntrance({ opacity: 0, transform: "translateY(14px)", ...spring("snappy") }),
animateExit({ opacity: 0, transform: "translateY(14px)", ...spring("snappy") }),
]} />Add and remove items to watch entrance and exit animations driven by the selected spring.
Layout
animation · animateLayoutFLIP-style projection animates position and size changes between renders.
<div mix={animateLayout({ ...spring("smooth") })} />