The standard index page — Page header, a sticky toolbar (search, filters, saved views, view switch), a bulk-action bar that takes the toolbar's place, the content (table, grid or board) and footer pagination — with one consistent set of loading, refreshing, empty, no-results and error states. It arranges and announces; filtering, selection and data fetching stay with your Data Table and data layer.
Contacts
| Name | Stage | Owner | Value | |
|---|---|---|---|---|
| Laura CallahanNorthwind Traders | Customer | Meltem Aydın | $48,500 | |
| Jonas WeberKessler Logistik | Proposal | Can Demir | $22,000 | |
| Priya NairLotus Health | Qualified | Meltem Aydın | $15,750 | |
| Kenji SatoHikari Studio | Lead | Ece Yılmaz | $6,200 | |
| Amara OkaforBaobab Energy | Customer | Can Demir | $91,300 |
1–20 of 1,284
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { ListLayout, ListToolbar, ListViewSwitch, ListBulkBar, ListContent, ListFooter, PageHeader, PaginationBar } from "@vamos-ui/react";
<ListLayout>
<PageHeader title="Contacts" meta={<Badge>1,284</Badge>} actions={<Button variant="primary">New contact</Button>} />
<ListToolbar
search={<Input leading={<Search />} placeholder="Search contacts" aria-label="Search contacts" />}
filters={<FilterBar … />}
filterCount={2}
viewSwitch={<ListViewSwitch value={view} onValueChange={setView} options={[{ value: "table", label: "Table" }, { value: "board", label: "Board" }]} />}
/>
<ListBulkBar count={selected.length} total={1284} onSelectAll={selectAll} onClear={clear}>
<Button size="sm">Assign owner</Button>
</ListBulkBar>
<ListContent state={state} resultCount={1284} onRetry={refetch} onClearFilters={clearFilters}>
<DataTable … />
</ListContent>
<ListFooter><PaginationBar total={1284} page={page} pageSize={20} onPageChange={setPage} /></ListFooter>
</ListLayout>Selection lives in your Data Table; ListBulkBar is presentational. The same goes for filters and saved views.
Built-in strings use the list namespace: selected, selectAllCount, allSelected, clear, filters, filtersCount, results, refreshing, noResults, clearFilters, error, retry.
Examples
States
Every ListContentState. refreshing keeps the rows and shows a thin bar; the change is announced in a polite live region ("3 results"). Override any placeholder with empty / noResults / error / skeleton.
Selection and bulk bar
The bar replaces the toolbar while count > 0 and announces "2 selected". "Select all 312" widens the selection across pages (allSelected). Esc clears and focus returns to the toolbar.
- Selin ÖztürkProduct designerDesign
- Marcus LindqvistBackend engineerPlatform
- Aylin ÇelikPeople partnerPeople
- Tomás RibeiroAccount executiveSales
Grid view
ListViewSwitch is a radio group with one tab stop; arrow keys move, Space selects. A CMS media library with a "Load more" footer.
Media
6 of 418 files · 1.9 GB used
dining-room-dusk.jpg
2.4 MB
menu-spring-2027.pdf
860 KB
team-offsite.jpg
3.1 MB
logo-mark.svg
12 KB
grilled-sea-bass.webp
1.2 MB
studio-window.jpg
2.9 MB
Phone width
The layout responds to its own width: below ~640px filters fold into a "Filters (3)" sheet and the view switch shows icons only.
Partners
Atlas Distribution
Gold · EMEA
Brightline Resellers
Silver · North America
Kumo Partners
Gold · APAC
API
ListLayout
| Prop | Type | Default |
|---|---|---|
widthMax width: none · 90rem · 76rem. | "full" | "wide" | "content" | "full" |
stickyToolbarToolbar and bulk bar stick under the top bar on the bar surface. | boolean | true |
stickyTopSticky offset. Use 0 inside your own scroll container. | number | string | "var(--topbar-h)" |
ListToolbar
| Prop | Type | Default |
|---|---|---|
searchSearch field, wrapped in a role="search" landmark. | ReactNode | — |
searchLabelName of the search landmark. | string | "Search" |
filtersFilter chips / Filter bar. Fold into a sheet below ~640px. | ReactNode | — |
filterCountActive filters, shown on the folded "Filters (3)" button. | number | — |
viewsSaved views — a row above the search. | ReactNode | — |
viewSwitchUsually a ListViewSwitch. | ReactNode | — |
actionsTrailing actions: export, columns, ⋯. | ReactNode | — |
labelsOverrides for the list namespace. | ListLayoutLabels | — |
ListViewSwitch
| Prop | Type | Default |
|---|---|---|
optionsViews. With an icon the label hides on narrow lists (still the accessible name). | { value: string; label: string; icon?: ReactNode }[] | — |
value · defaultValue · onValueChangeControlled or uncontrolled. A view is always selected. | string | — |
labelAccessible name of the radio group. | string | "View" |
ListBulkBar
| Prop | Type | Default |
|---|---|---|
countSelected rows. The bar shows while count > 0. | number | — |
totalAll matching rows; enables "Select all {total}". | number | — |
onSelectAllSelect every matching row across pages. | () => void | — |
allSelectedShows "All {total} selected". | boolean | — |
onClearClear button and Esc. | () => void | — |
childrenBulk actions. | ReactNode | — |
ListContent
| Prop | Type | Default |
|---|---|---|
stateWhat the content area shows; loading and refreshing set aria-busy. | "ready" | "loading" | "refreshing" | "empty" | "no-results" | "error" | "ready" |
empty · noResults · error · skeletonReplace the default placeholders. | ReactNode | — |
onRetryAdds "Try again" to the default error state. | () => void | — |
onClearFiltersAdds "Clear filters" to the default no-results state. | () => void | — |
resultCountAnnounced politely when the list becomes ready. | number | — |
skeletonRowsRows in the default skeleton. | number | 6 |
ListFooter
| Prop | Type | Default |
|---|---|---|
classNameRow under the content: PaginationBar, Load more, a summary. | string | — |