Rail nav
The compact navigation of an application: a vertical rail of icons on a desktop — the product's mark on top, a tooltip on each icon, an accent bar on the current one, a footer for settings and the account — that becomes a bottom tab bar on a phone. Paired with AppHeader, which carries the product's name (and, on a phone, its mark).
import { RailNav } from "@krizaka/ui/rail-nav";Web only — React, from @krizaka/ui/rail-nav. Beta: its API may still change in a minor version.
- Mobile · n/a. On a phone the rail is already a bottom tab bar; a native app uses the TabBar. → Tab bar
Why it is here. Used by Orazaka, Yomizaka, Akinaza.
When to use
- An application with three to eight destinations the user works in all day (Home, Studios, Chat, Jobs, Settings) and little else in the way: the rail leaves the screen to the work.
- When the same sections must read as a vertical rail on a desktop and as tabs on a phone, written once.
When not to use
Installation
Install
npm install @krizaka/ui @krizaka/tailwind @krizaka/tokens tailwindcssStyles
@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";Import
import { RailNav } from "@krizaka/ui/rail-nav";Examples
A studio
Orazaka's signed-in app: the mark on top of the rail, five sections with the current one lit, settings at the foot, the header with the name and a status chip.
Shortcuts and the family's bar
Akinaza's frame: the rail with a « Shortcuts » group above the expand toggle, expanded from 1280 px, and the family's top bar — search, notifications with a count, the account with its name from 1024 px.
Expandable
The same rail with a button that widens it to show the words, for users who do not know the icons yet.
Props
RailNavRoot
The rail: a vertical column of icons on a desktop, a bottom tab bar on a phone.
| Prop | Type | Default | Description |
|---|---|---|---|
childrenrequired | ReactNode | — | The main destinations: RailNav.Item, the ones you work in. Five at most so that they fit a phone's tab bar. |
labelrequired | string | — | The navigation's accessible name (Orazaka, Studio). |
accent | BrandId | — | The product's brand: scopes its colours (brand-orazaka…) over the rail, so the accent follows. Omit it inside a page that already wears the brand. |
defaultExpanded | boolean | — | The starting width when uncontrolled. Unset: expanded from 1280 px (the words fit there), narrow below — until the person toggles it. |
expandable | boolean | — | Adds a button that widens the rail to show the words (desktop only). Needs expandLabels. |
expanded | boolean | — | Controlled width (pair with onExpandedChange to keep the choice). |
expandLabels | readonly [string, string] | — | The toggle's words, [expand, collapse]. |
footer | ReactNode | — | At the foot of the rail (settings, account), after the main items; on a phone they follow them in the same bar. RailNav.Items or a control with data-rail-item. |
mark | ReactNode | — | The product's mark on top of the rail, as a link home (<Link href="/"><ProductLogo id="orazaka" /></Link>); named by the app (its aria-label). Hidden on a phone: AppHeader shows it there. |
onExpandedChange | ((expanded: boolean) => void) | — | Called when the toggle widens or narrows the rail. |
shortcuts | ReactNode | — | The product's shortcuts (RailNav.Items: a saved view, a client, « New invoice »), a group above the footer and the expand toggle. Desktop only: a phone's tab bar keeps its destinations. |
shortcutsLabel | string | — | The shortcuts' heading (« Raccourcis », « Shortcuts ») — passed translated: the group's name, shown once the rail is expanded. |
RailNavItem
A destination of the rail.
| Prop | Type | Default | Description |
|---|---|---|---|
iconrequired | ReactNode | — | The item's icon (a signature icon of @krizaka/icons): all that shows on a desktop rail. |
labelrequired | string | — | Its words: the accessible name, the tooltip, the tab's caption on a phone, the row's text when the rail is expanded. |
asChild | boolean | — | Renders your router's link with the item's look: pass it as the only child. |
badge | ReactNode | — | A count (unread, pending) on the icon. Say it in words with badgeLabel. |
badgeLabel | string | — | The count in words (« 3 unread »), appended to the accessible name. |
current | boolean | — | This is the section the user is in: aria-current="page", the accent bar and the accent colour. |
Accessibility
- A
navnamed bylabel; the current item carriesaria-current="page". - The shortcuts are a
groupnamed byshortcutsLabel(its heading, visible once the rail is expanded); the arrows walk through them like the other items. - Each item is named by its
label(andbadgeLabel): the tooltip and the caption repeat it, they never replace it. - The focus ring is the Krizaka signature (
focus-ring-inset), kept inside the rail's edge so it is never clipped. - A tab is at least 56 px tall, clear of the home indicator (
env(safe-area-inset-bottom)); the motion of the width respectsprefers-reduced-motion. - Exactly one brand mark is visible at every width: the rail's
markbelowmdis hidden andAppHeader'smarkis shown there, and the reverse above.
Keyboard
| Keys | Action |
|---|---|
| Tab | Moves through the items, the footer's controls and the expand button. |
| ↑ ↓ (rail) · ← → (tab bar) | Moves the focus to the previous or next item, wrapping at the ends; both pairs always work. |
| Home / End | Focuses the first or the last item. |
| Esc | Dismisses a tooltip that is showing. |
Best practices
- Five main items at most: on a phone they are the tabs (the footer's items follow them in the same bar, so keep both short).
- Give every item an icon and a word: the icon is all a desktop shows, the word is the tooltip, the tab's caption and the accessible name.
- Put the product's mark in
markand its name inAppHeader: the mark is shown once, in the rail on a desktop and in the header on a phone. Never draw it in both. - Render your router's links with
RailNav.Item asChild; setcurrentfrom the route. - Scope the product's colours with
accent(orazaka,yomizaka…) or let the page's brand class do it. expandableis for apps whose users know the icons less well: it widens the rail to show the words. Uncontrolled and withoutdefaultExpanded, it is expanded from 1280 px (the words fit there) until the person toggles it.shortcuts(withshortcutsLabel, « Raccourcis ») holds the product's quick ways in — a saved view, a frequent client, « New invoice » — above the footer; two to four, never a second navigation. Desktop only: a phone's tab bar keeps its destinations.
Related components
Generated from the code of @krizaka/ui 3.63.1: its meta.ts, its examples and its types.Edit this documentation on GitHub