Skip to content

Component tour

This page shows each built-in building block once, with the declaration that asks for it and a link to it in the component library, where you can switch between the seven looks, light and dark.

The library is Storybook, built with this site. Each story draws the real component from src/client/components over fixture data, with no server behind it. The pictures here are in Mono, the default look. The Look and Mode buttons in the library’s toolbar dress any story in the others.

A list view is a grid unless its presentation says otherwise. The rows, the filters and the permissions don’t change with the presentation. See lists and list views.

A task list in a grid: tabs with counts, a search box, a status filter chip, sortable column heads, and statuses as a dot and a word.

Grid: the default, with tabs, filters, Sort and a selection. listView('Tasks', 'task', { show, tabs, filters }) · Open in the library

Vehicle cards: a photo, a title, a price and a line of facts on each.

Cards: a picture, a figure and a line of facts. cards('title', { value, facts, image }) · Open in the library

A queue of tasks: each row a title, its status badge, a line of facts and an Open button.

Queue: compact rows made to work through. queue('title', { badge, lines, facts }) · Open in the library

A board of task cards in lanes by status, with lane counts.

Board: lanes by one column; a drag is an ordinary update. { kind: 'board', by: 'status', primary } · Open in the library

A month calendar with a task on each of several days.

Calendar: a month by one date column, or ranges with end. calendar('due_on', 'title') · Open in the library

A split inbox: a list of tasks on the left, the selected task’s details on the right.

Split: the list beside the picked record. { kind: 'split', detail } · Open in the library

A record page is a list of sections. See record pages.

A record page: the record’s name, its fields grouped under headings, and a context column.

Fields: grouped values, edited in place where the reader may write. fields(['name', 'status'], { title: 'Details' }) · Open in the library

A related list of invoices under an account: name, status, account, amount due and due date.

Related list: the rows that point at this record. related('Invoices', 'invoice', 'account_id', { show }) · Open in the library

A record’s history: who changed which field, from what to what, and when.

History: the record's own changes, newest first. history() · Open in the library

A workflow strip: Submitted, In review (current), Approved, Issued.

Workflow: where the record stands. fields(['status'], { workflow: workflow('status', steps, { ordered: true }) }) · Open in the library

A dashboard is a list of sections about whole tables. On a record page, the same helpers take whose and count only the rows that point at that record. See dashboards.

Three stat cards: a figure, its change against the compare window with a trend line, and a target meter.

Metrics: a figure, its change and a target. metric('Open tasks', 'task', { query, better: 'down' }) · Open in the library

A bar chart of counts by month, the current bar marked.

Charts: lines, bars, stacked bars and donuts. chart('Created', 'task', 'month created_on', { shape: 'bar' }) · Open in the library

A breakdown: work by status as solid bars with their counts.

Breakdowns: a count per value, in its vocabulary's order, else biggest first. breakdown('Work by status', 'task', 'status') · Open in the library

An activity feed: Today, Yesterday and This week, a search, and four changes, each with what the write did, the record, the field from what to what, who and when.

Activity: recent changes across resources, as the reader may read them. activity('Latest updates', { task: { icon: 'list-checks' } }) · Open in the library

A first run: a welcome with two numbered steps, each with a button to open its list.

First run: next steps in place of a dashboard of zeros. firstRun('Welcome', [{ label, view }]) · Open in the library

The same stat cards in Tray: each card a white card inside a light-grey tray, its mark in the tray’s title strip.

The same metrics in Tray, the analytics look: each section a grey tray holding one white card. ui: { theme: { preset: 'tray' } } · Open in the library

The New form comes from the resource. A command’s form comes from its declared inputs. See forms and command forms.

A guided request form: a step indicator, labelled fields with hints, and Continue.

Guided form: a command form in steps. commandForm('Request', ref, [step('About you', [...])]) · Open in the library

Command fields with a repeating group of lines, each with an item and a quantity.

Declared inputs, including a repeating group. field.group({ … }, { repeat: { min: 1, max: 30 } }) · Open in the library

The sign-in screen, the account menu and the bell come with auth. You don’t declare them. See sign-in, roles & data.

The sign-in screen: the App’s name, email and password fields, and a Sign in button.

Sign-in: the App's front door. auth: { providers: ['email'] } · Open in the library

The account menu open under the signed-in name: Your profile, Manage accounts, Sign out.

Account menu: profile and settings; Manage accounts for an admin. · Open in the library

The bell open: three notifications, two unread, with Mark all read.

Bell: the reader's notifications, from a resource's notify rules. · Open in the library

Where no built-in fits, an App draws its own with a React module and tablewalk/ui. Each sample module’s examples are also stories in the library, under Sample Apps. See custom components.

Commons’s post stream: posts with avatars, photos, reactions, and Reply and Report.

Commons: post stream, a list view's rows drawn by the App. customList(postStream, { show }) · Open in the library

Depot’s bin map: two aisles of bins shaded by how full each is, a reserve and a dock.

Depot: bin map, a page section fed by declared reads. custom('Floor', binMap, { rows }) · Open in the library
Terminal window
npm install && (cd storybook && npm install)
cd storybook && npm run dev # http://localhost:6006

npm run build:site builds it into site/dist/components/.