Blocks are whole screens and frames, finished: pass the data and callbacks, get the page. A sidebar is the
same logic in every app, so an app passes navigation and nothing else; a list is the table block plus
rows and columns. Each block is assembled from parts that are exported too, so you can use one small piece
alone or build a variant from the same parts.
import { AppShell, ListPage, ListTable } from '@arbol-ai/ui';
<AppShell navigation={navigation}>
<ListPage title="Contacts" count={total} actions={<NewContactButton />}>
<ListTable
aria-label="Contacts"
columns={columns}
data={contacts}
getRowHref={(contact) => `/contacts/${contact.id}`}
/>
</ListPage>
</AppShell>;| Block | What it brings |
|---|---|
AppShell and its slots |
Sidebar from items, header, back link, companion panel; AccountMenu, OrganizationMenu, LogoTile, ProductMark |
ListPage, ListTable |
Toolbar (search, filters, saved views, columns), sorting, row links and menus, every state, pages, bulk actions |
RecordPage, SettingsPage |
Record header with pager and rename, tabs, properties aside; settings sections, cards, links and save bar |
FormDialog, FormSheet (/form) |
A create or edit flow: fields, Cancel and a pending Submit, the server’s refusal, the discard guard |
KpiGrid, ChartCard, ReportPage |
A period picker, KPI tiles from data, chart cards from series, breakdowns |
| Route states | RouteErrorState, NotFoundState, NoAccessState, AppLoadingState, and TanStack Router adapters in /router |
Tables, forms, routing, data fetching and virtualization are all TanStack: Table (DataTable), Form,
Router, Query and Virtual (PickList).