Data view
The loading, empty, and error shell every data display needs. Wrap a Table, CardList, or Board and let the view own the four states so pages stop rebuilding them.
DataView is a family of four thin shells — TableView, ListView, ProfileView, BoardView — that own the loading, empty, and error states every data display needs. Pass the display primitive (Table, CardList, a DataSection stack, a Board) as children; the view renders exactly one state in precedence order — error → loading → empty → content. It exists so consumers stop hand-rolling a skeleton, an EmptyState, and an error Banner on every page.
Use it for
- Wrapping any async data display that needs loading / empty / error handling
- A Table, list, profile, or Board that loads from the network
- Standardizing the four data states across a product so they look and behave identically
Import
Each shape has its own named view — they are distinct components, not one polymorphic variant, each carrying a display-shaped default skeleton.
import { TableView, ListView, ProfileView, BoardView } from '@brikdesigns/bds';Variants
TableView
Wrap a Table; the default loading skeleton is a header row plus body rows. Toggle loading, empty, or error to switch state.
<TableView
loading={isLoading}
error={error}
empty={rows.length === 0}
emptyState={{ title: 'No items yet', description: 'Add your first record.' }}
>
<Table>{/* … */}</Table>
</TableView>ListView, ProfileView, BoardView
Same prop surface, different display-shaped skeleton — a card list, a profile section stack, and a horizontal column board respectively.
<ListView loading={isLoading} empty={items.length === 0} emptyState={{ title: 'No items' }}>
<CardList>{/* … */}</CardList>
</ListView>
<BoardView loading={isLoading} empty={lanes.length === 0} emptyState={{ title: 'No lanes yet' }}>
<Board>{/* … */}</Board>
</BoardView>Empty state as a ReactNode
emptyState accepts either a config object (renders EmptyState) or any ReactNode for full control.
<ListView empty emptyState={<MyCustomEmpty />}>
<CardList>{/* … */}</CardList>
</ListView>Custom skeleton
skeleton overrides the display-shaped default when you want a higher-fidelity match to the real content.
<TableView loading skeleton={<MyTableSkeleton />}>
<Table>{/* … */}</Table>
</TableView>When not to use
- Don't swallow errors.
errorrenders a loud error Banner by design — pass the real error string; don't catch-and-hide. - Don't build a fifth polymorphic view. The four shapes are distinct components on purpose. A new display shape gets its own thin shell, not a
variantprop.
Accessibility
- Loading skeletons are marked
aria-hidden="true"so assistive tech skips the placeholder and announces content when it arrives. - The error state renders a Banner with
tone="negative"; the empty state renders EmptyState — each carries its own semantics.
API
The same surface on every view.
| Prop | Type | Default |
|---|---|---|
loading | boolean | — |
error | string | null | — |
errorTitle | string | "Couldn't load" |
empty | boolean | — |
emptyState | DataViewEmpty | — |
skeleton | ReactNode | — |
children | ReactNode (required) | — |
emptyState is a DataViewEmptyConfig ({ title, description?, buttonProps? }) or any ReactNode.
Related
- Table — the display TableView wraps
- CardList — the display ListView wraps
- Board — the display BoardView wraps
- EmptyState — rendered for the empty state
- Banner — rendered for the error state
- Skeleton — the loading-state primitive
- Storybook playground