KQ-2104 · DOUBLE/RAIL

Double Rail

An app frame with two tiers of navigation: a slim rail of sections whose pill slides on springs.snap, and a panel listing what is inside the chosen one. Changing section slides the panel's list sideways on springs.glide in the direction of travel while its title and count carry over as shared elements — the title cross-fades in place, the count glides to sit after it and rolls to its new number on snap; on a phone the section row's title and count fly into the drilled header. Up and Down move within a tier, Right crosses from rail to panel, Left comes back.

KQ-2104 · DOUBLE/RAIL
ML
Fleet

Vehicles

Upkeep

Fleet / Vans

Vans

Light vans across the four Yorkshire depots.

Total
24
On route
14
Service due
2
  • GW-1088Panel van · HullIn depot
  • GW-1726Panel van · YorkOn route
  • GW-1059Panel van · WakefieldOn route
  • GW-1604Panel van · LeedsOn route
  • GW-1296Panel van · WakefieldIn depot

gaugeworks · fleet · vans · 24

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/double-rail

Props

sections
RailSection[]
default defaultRailSections
Sections for the rail, each with its icon, count and grouped secondary list; loading and empty sections are states, not errors.
section / defaultSection
string
default — / the first section
The current section id, controlled or uncontrolled.
onSection
(id: string) => void
default —
Fires from the rail (click or arrows) with the section chosen.
page / defaultPage
string
default — / the first item
The current page: an item id, unique across sections.
onNavigate
(sectionId: string, itemId: string) => void
default —
Fires whenever the current page changes, including when a section change brings its remembered page.
collapsed / defaultCollapsed
boolean
default — / false
Whether the panel is folded away, controlled or uncontrolled.
onCollapse
(collapsed: boolean) => void
default —
Fires from the toggle, or when choosing a section reopens the panel.
onEmptyAction
(sectionId: string) => void
default —
An empty section's action button was pressed.
panelWidth
number
default 220
Width of the secondary panel, px.
slideDirection
"sideways" | "vertical" | "fade"
default "sideways"
How the panel's list moves when the section changes: sideways in the direction of travel, vertically with the rail, or a cross-fade.
accent
string
default "var(--accent-bright)"
The rail pill, the current page and counts in the current section — any CSS colour.
renderPage
(section: RailSection, item: RailItem | null) => ReactNode
default —
Draws the page in place of the built-in one.
product
string
default "Gaugeworks"
The product's name, on the rail's mark and in the phone header.
user
string
default "Mara Lindqvist"
Who is signed in, for the rail's avatar.
status
"ready" | "loading" | "error"
default "ready"
Whether the navigation has arrived.
onRetry
() => void
default —
Try again was pressed after the navigation failed to load.
height
number
default 520
The frame's height, px.
className
string
default —
Classes for the outer frame.