RoadieRoadie
  • Home
  • Brand
  • Foundations
  • Content
  • Tokens
  • Components
  • Charts
  • Widgets
  • Appearance
HomeBrandFoundations
Appearance

Foundations

  • Visual

    • Colors
    • Elevation
    • Iconography
    • Shape
    • Theming
  • Content

    • Date and time
    • Layout
    • Prose styles
    • Typography
  • Behaviour

    • Accessibility
    • Interactions
    • Motion
    • View transitions
  • Building apps

    • Forms
    • Linking
    • Navigation
    • Performance
    • Records modelAlpha
    • Tables

Tables

Docs updated
23 Oct 2026

Roadie has one table for working through records and one for reading a summary. Pick by what people do with the rows, then shape the columns so the same record reads the same way in a pane, in a dashboard, and on paper.

Choose by job

ComponentUse it forWhere it livesRows
RecordTableA working list people search, sort, select, and page through. Turns into list rows or cards when narrow.A Pane, most of the timeAny number
DataTableA read-only summary. Renders on the server, so it also prints in reports, PDFs, and slides.A DataCard on a dashboard, a detail page, or a PDFAbout 25 or fewer
ListA few records to open, or settings. No columns to compare.A detail page, a menu pane, or settingsAbout 10 or fewer
Card gridBrowsing where an image leads, like event tiles. No sorting.A home or discovery pageA screen or two
StatTileOne number that matters, with its change.A dashboard row or the top of a detail pageOne value

Signs you picked the wrong one

  • A DataTable gains a search box or a pager. It has become a working list. Use a RecordTable.
  • A RecordTable holds five rows nobody searches. Use a DataTable, or a List when each row opens something.
  • A card grid gets sort controls. People are comparing, not browsing. Use a RecordTable.
  • A dashboard card lists people or orders. Show the count in a StatTile and link to the pane that lists them.
  • A table has one row. Show the values as a StatTile or a description list.

Work in a RecordTable, read in a DataTable

<RecordTable
caption='Orders'
data={orders}
fields={fields}
columns={columns}
/>

Do

Give people a RecordTable when they search, sort, or page through the rows.

<DataTable
caption='Orders'
columns={columns}
rows={allOrders} // 4,812 rows
/>

Don’t

Don't put a long list people need to search into a DataTable. It renders every row and has no search or paging.

Records live in a Pane

Most RecordTables fill a Pane: the title in the header, the toolbar with its search above the rows in the body, and the pager in the footer. Keep the search in the table's toolbar, not in Pane.Search. The RecordTable page has a complete pane to copy.

Columns

  • Describe the record once. Build its fields with recordFields, then build columns from them with tableColumns. A field's type decides how its values read, everywhere it shows. See Records model.
  • One title column. Pin it with pin: true. A column with narrow: 'title', or else the first pinned text column, or else the first text column, reads as the row's title, in strong text.
  • Numbers end-aligned. Number and money fields do this, and sort largest first.
  • Money. currency where cents matter, an order total or a payout. compactCurrency for gross across events, where $118k reads faster than $118,400. A field with currencyKey names any currency that isn't dollars.
  • Dates. Event and access dates read in the venue's zone through timeZoneKey, long with the weekday. Timestamps read in the reader's zone, medium with the time. See Date and time.
  • Status as a Badge. Give an option field a status map of each key to its intent, chosen by meaning. It shows a small Badge in normal emphasis and sorts by each key's order.
  • Ids in monospace. Order numbers, references, and promo codes, through font-mono in the column's cell.
  • Give each column its place on a phone. Under 40rem the table lists its records. The title column takes narrow: 'title', one line under it 'description', and a status 'trailing'. Any 'detail' column turns rows into cards; keep it to three or four details. The rest stay in the wide table.
  • Let the extras go first. Give columns people can do without a priority so they hide as the table narrows, 3 first, before it turns into list rows.
  • Images lead. An image column, with kind: 'image', shows a thumbnail, leads a list row, and becomes a card's banner.
  • Hide the rest. A view's layout.columns.hidden hides columns, and its order reorders them. Pinned columns stay first and shown.

Totals

  • Add a totals row when the totals belong to columns, so people read down a column to its total: sold, gross, and capacity across events. For two or three headline numbers that don't map to columns, show StatTiles above the table instead.
  • Total every record that matches, never just the page. A server sums the matches, and the totals follow the search and filters.
  • A RecordTable shows its totals under the headings, since its last row is only the end of a page. A DataTable shows them in its footer, under every row, as an invoice does.
  • The label, such as "Totals for 1,234 shows", goes in the title column. With no title, it takes the first column without a sum, so it never covers a total. RecordTable and DataTable follow the same rule.
  • Add up counts and amounts only. Work a ratio out from the sums, such as total sold over total capacity, never by adding up or averaging each row's.
  • See Totals on the RecordTable page and DataTable.

Table examples

Orders

A working list in its own box, newest first. The order number is the pinned title, in monospace through its cell, and the status reads as a Badge. Under 40rem each row shows the customer under the order number and the status on the end.

const customers = ['Mia Tran', 'Jack Ellis', 'Ava Nguyen', 'Noah Smith', 'Isla Brown', 'Leo Wilson']
const eventNames = ['Ochre Kite Weekender', 'Marzipan Thunderclap', 'Corduroy Lagoon Sessions', 'Velvet Dingo Fest']
const statuses = ['paid', 'paid', 'paid', 'pending', 'refunded']
const orders = Array.from({ length: 60 }, (_, index) => ({
id: `order-${index}`,
number: `OZ-${48210 + index * 7}`,

Top events in a dashboard

A DataTable in a DataCard. Five rows, sorted by gross, with the venue as secondary text and sell-through as a meter.

<div className='w-full max-w-md'>
<DataCard
label='Top events'
takeaway='Ochre Kite Weekender leads gross this month'
source='Oztix sales. Gross before fees.'
>

Oztix records by context

Each record lists its RecordTable columns with the type of the field behind each one, how it reads, where it goes on a phone (narrow), and which hide first as the table narrows (priority), then how the record appears everywhere else.

Event

A show or session at a venue. The record most panes start from.

ColumnField typeShows asNarrowPriority
Event (pinned)textStrong texttitle
VenueoptionOption labeldescription
StatusoptionBadgetrailing
Start datedateLong date and time in the venue's zone (Fri 27 Nov 2026, 7:30pm)detail
SoldnumberNumberdetail
CapacitynumberNumber2
GrossmoneyCompact currencydetail
ContextHow it shows
In a PaneSearch by event or venue. Sort by start date, soonest first. See the Events pane example.
On a phoneCards: the event, the venue under it, and the status on the end, with starts, sold, and gross as details.
DashboardTop events: Event with the venue as secondary text, a sell-through meter, and Gross. Sort by gross, largest first. Five rows.
Detail pageThe event page leads with image, date, and venue, then stat tiles for sold, gross, and sell-through. Ticket types sit in a DataTable.
PDF or reportAn event report: the ticket type DataTable, plain, and charts drawn with renderChartSvg.

Order

One purchase by one customer, holding one or more tickets.

ColumnField typeShows asNarrowPriority
Order (pinned)textMonospace order numbertitle
CustomertextTextdescription
EventoptionOption label2
StatusoptionBadgetrailing
PlaceddateTimestamp in the reader's zone (27 Nov 2026, 2:14pm)3
TotalmoneyCurrency
ContextHow it shows
In a PaneSearch by order number or customer. Newest first.
On a phoneList rows: the order number, the customer under it, and the status on the end.
DashboardNot as a list. Show the order count in a StatTile and link to the Orders pane.
Detail pageOrder number and status, the customer, the event, then line items in a DataTable: ticket type, quantity, price, and subtotal.
PDF or reportA tax invoice: the line items DataTable, plain, with totals in currency.

Attendee

One ticket and the person holding it. One order can hold several.

ColumnField typeShows asNarrowPriority
Name (pinned)textStrong texttitle
EmailtextText2
Check-inoptionBadgetrailing
Ticket typeoptionOption labeldescription
OrdertextMonospace order number3
Checked in atdateTimestamp in the reader's zone3
ContextHow it shows
In a PaneSearch by name or email. Sort by name.
On a phoneList rows at the door: the name, the ticket type under it, and check-in on the end.
DashboardEntry by gate: Gate, Checked in, and Inside as a meter of the share now in the venue. One row per gate.
Detail pageThe ticket: holder, ticket type, barcode, and scan history, with transfer and resend actions.
PDF or reportA door list PDF: a plain DataTable per ticket type, sorted by surname. Render it on the server.

Customer

A person who has bought from a client, with their contact details and history.

ColumnField typeShows asNarrowPriority
Name (pinned)textStrong texttitle
EmailtextTextdescription
SuburbtextText, searchable3
StateoptionOption label2
OrdersnumberNumber
SpendmoneyCurrencytrailing
Last orderdateDate and time in the reader's zone (27 Nov 2026, 2:14pm)3
MarketingbooleanYes or No
ContextHow it shows
In a PaneSearch by name, email, or suburb.
On a phoneList rows: the name, the email under it, and spend on the end.
DashboardAggregate, never list people. Where buyers are from: Suburb and share, five rows. New and returning buyers as StatTiles.
Detail pageContact details and marketing consent, then their orders.
PDF or reportLeave personal details out of reports.

Ticket type

A price and allocation on sale for one event, like General admission or VIP.

ColumnField typeShows asNarrowPriority
Ticket type (pinned)textStrong texttitle
PricemoneyCurrencydescription
StatusoptionBadgetrailing
SoldnumberNumber
AllocationnumberNumber3
GrossmoneyCompact currency
ContextHow it shows
In a PaneInside the event. Most events have fewer than ten, so a DataTable often does the job.
On a phoneList rows: the ticket type, the price under it, and the status on the end.
DashboardTicket type mix: Ticket type, Sold, a sell-through meter, and Gross. Sort by sold, largest first.
Detail pageThe event page shows them in a DataTable: Ticket type, Price, Sold, and Gross.
PDF or reportThe settlement report lists them in a plain DataTable: Ticket type, Price, Sold, and Gross.

Payout

A payment to a client for one settlement period, covering one or more events.

ColumnField typeShows asNarrowPriority
Reference (pinned)textMonospace reference, searchabletitle
PerioddateDate range (Sun 1 to Sun 15 Nov 2026)description
StatusoptionBadgetrailing
PaiddateDate and time in the reader's zone (27 Nov 2026, 2:14pm)2
GrossmoneyCurrency
FeesmoneyCurrency3
NetmoneyCurrency
ContextHow it shows
In a PaneNewest period first. Search by reference.
On a phoneList rows: the reference, the period under it, and the status on the end.
DashboardThe next payout as a StatTile, with its period and date as context. Recent payouts: Period, Paid, and Net, three rows.
Detail pageA statement headed by its period: gross, booking fees, refunds, card fees, and net as a plain DataTable.
PDF or reportThe settlement statement PDF uses the same DataTable.

Refund

Money returned against an order, whole or in part.

ColumnField typeShows asNarrowPriority
Order (pinned)textMonospace order numbertitle
CustomertextTextdescription
AmountmoneyCurrency
StatusoptionBadgetrailing
ReasonoptionOption label3
RequesteddateTimestamp in the reader's zone2
ContextHow it shows
In a PaneA queue, oldest first. Search by order number or customer.
On a phoneList rows: the order number, the customer under it, and the status on the end.
DashboardPending refunds as a StatTile. Refunds by reason: Reason, Count, and Amount, five rows.
Detail pageShown on the order it belongs to, as a line in its history with the amount and reason.
PDF or reportFinance reconciles refunds from their lines in the settlement statement.

Promo code

A code that discounts tickets, with a usage limit and a date range.

ColumnField typeShows asNarrowPriority
Code (pinned)textMonospace codetitle
DiscounttextText (20% or $10)description
StatusoptionBadgetrailing
UsesnumberNumber
LimitnumberNumber3
RevenuemoneyCompact currency
EndsdateLong date (Fri 27 Nov 2026)2
ContextHow it shows
In a PaneSearch by code.
On a phoneList rows: the code, the discount under it, and the status on the end.
DashboardTop promo codes: Code, Uses, and Revenue. Sort by revenue, largest first. Five rows.
Detail pageThe code settings as a form, then the orders that used it.
PDF or reportIn a marketing report, the same three columns as a plain DataTable.
Previous page← Records modelNext pageOverview →