Design system/Components
Navigation
On desktop, two columns at the start edge of the screen: services, and whatever the current service opens into. On phones and tablets, the dock at the bottom of the screen. On desktop, the top bar shows the page name and its main action.
In codecomponents/side-nav.tsxcomponents/dock.tsxcomponents/app-header.tsxlib/section-nav.ts
Structure
The first column (84px) is services: tools pinned from settings, with the logo at the top and the account's own items at the bottom. The second column is what the current service contains: its real destinations from lib/section-nav.ts and, where available, its live items, like Library folders.
This is a diagram; the real sidebar and dock are attached to the window edge and only appear inside the app.
The second column belongs to the reader
The second column can be collapsed, and the choice is remembered, because the section whose items you know is the column you'd rather give to the page. Its width also changes from 200 to 440px by dragging the outer edge. The whole layout reads from one variable, --side-panel-w, so resizing means one number on html.
84px220px200–440 · draggable≥ 900pxhtml[data-sidenav=open|closed|none]Dock
Below 900px, the sidebar is hidden and the dock at the bottom of the screen handles navigation, with Quick add and the account menu. 900 and not 640, because the two columns need about 300px that a tablet doesn't have to spare.
Top bar
On desktop, the top bar shows the page name next to the plan badge; the page sends its title to the bar with PageHeader, and the in-page title is hidden only when the bar says it's showing it. The page's main action, like "New person" or "Event", sits next to the title through useHeaderAction; the page sends it because the bar doesn't know whether this user is allowed to do that.
Rules
Do
Add a new internal route to INNER_ROUTES.
Don't
A new internal page without it; it renders with no bar and no dock.
Do
Define a section's destinations in lib/section-nav.ts.
Don't
A separate list in the sidebar and the dock.
Sizes
padding 9px 4px · radius 12px · gap 5px≥ 900px--text on --muted · 0.14sinset-inline-start 20px · bottom 20px · z 75padding 9px 10px · radius 10px · 13px / 500min-height 48px · padding 12px · radius 14px · 16.5pxIcon 20px21px · 12px200–440pxflowra.sidenav.widthAccessibility
- The sidebar has the aria-label “Navigation”, and the current destination has aria-current="page".
- The button that expands and collapses the second column has aria-expanded and the aria-label “Open the sidebar” or “Collapse the sidebar”.
- The resize handle has role="separator" and aria-orientation="vertical" but only works by dragging; the width can't be changed with the keyboard.
- The dock menu button has aria-haspopup="menu" and aria-expanded; Quick add has its own aria-label.
- The chat column filters have aria-pressed.
- The open or collapsed state is saved in flowra.sidenav and the width in flowra.sidenav.width, and the width only when cookie preferences have been accepted.
- On phones, the dock slides away when scrolling down and comes back when scrolling up.
Related pages