Skip to content

Data components

Show, sort, page and reorder data. Tables expose aria-sort, trees follow the WAI-ARIA tree pattern, and long lists stay fast with virtual scrolling.

11 components on this page. Every demo is live — change the theme in the header or flip a demo to right-to-left with its RTL button. 8 of them are React-only for now; Vue, Svelte and Angular versions are coming.

DataTable Link to DataTable

A sortable table with skeleton loading rows, custom cells and an accessible caption.

Live demo
Team members
Status
OSOmar SalehEngineering12Active
YKYousef KarimEngineering9Active
LHLina HaddadDesign7Active
SNSara NasserProduct4Away
MFMaya FaresDesign3Active

Props

PropTypeDescription
columns DataColumn<T>[] { key, label, sortable?, align?, render?, sortValue? }.
rows T[] Data.
loading / loadingRows boolean / number Skeleton rows while loading.
defaultSort / onSortChange { key, direction } Initial sort and change callback.
remote boolean Sort on the server — the table only reports changes.
caption string Table name for screen readers.

Accessibility

DataTable keyboard support
KeyAction
Tab Moves between sortable column headers
Enter / Space Toggles the sort on the focused header

Sorted headers set aria-sort; loading rows are announced once as a status instead of as empty cells.

Code

DataTable · React
<DataTable
  caption="Team members"
  rows={members}
  loading={isLoading}
  columns={[
    { key: 'name', label: 'Name', sortable: true },
    { key: 'projects', label: 'Projects', sortable: true, align: 'end' },
    { key: 'status', label: 'Status', render: (m) => <Badge>{m.status}</Badge> },
  ]}
/>

Tree Link to Tree

Hierarchical data with expand/collapse, single, multiple or checkbox selection, filtering and lazy loading.

Live demo
  • src

Checked: app

Props

PropTypeDescription
nodes TreeNode[] { key, label, icon?, children?, leaf? }.
label string Accessible name (required).
selectionMode 'single' | 'multiple' | 'checkbox' Selection behaviour.
selectedKeys / onSelectionChange string[] Controlled selection.
onExpand (node) => TreeNode[] | Promise Lazy-load children.
filter boolean Adds a filter box.

Accessibility

Tree keyboard support
KeyAction
Arrow Down / Arrow Up Next / previous visible node
Arrow Right / Arrow Left Expand or go to child / collapse or go to parent (mirrored in RTL)
Home / End First / last node
Enter / Space Select or check the node

role="tree" with aria-expanded, aria-level, aria-setsize and aria-posinset on each treeitem.

Code

ReactComing to Vue, Svelte and Angular.

Tree · React
<Tree label="Project files" selectionMode="checkbox" filter
  nodes={[{ key: 'src', label: 'src', children: [{ key: 'app', label: 'App.tsx' }] }]}
  selectedKeys={keys} onSelectionChange={setKeys} />

TreeTable Link to TreeTable

A table whose rows expand into child rows, with sortable columns.

Live demo
Owner
EngineeringOmar$420,000
Web platformYousef$180,000
MobileRami$140,000
InfrastructureAdam$100,000
OperationsSara$90,000

Props

PropTypeDescription
columns TreeTableColumn<T>[] Same shape as DataTable columns.
nodes TreeTableNode<T>[] { key, data, children? }.
caption string Table name (required).
defaultExpandedKeys string[] Initially open rows.

Accessibility

TreeTable keyboard support
KeyAction
Arrow Down / Arrow Up Move between rows
Arrow Right / Arrow Left Expand / collapse the row
Home / End First / last row

Uses role="treegrid" so screen readers announce row level and expanded state.

Code

ReactComing to Vue, Svelte and Angular.

TreeTable · React
<TreeTable caption="Budget" nodes={budget} defaultExpandedKeys={['eng']}
  columns={[{ key: 'name', label: 'Team' }, { key: 'cost', label: 'Cost', align: 'end', sortable: true }]} />

DataView Link to DataView

Render items as a list or grid with a layout toggle, sorting and built-in pagination.

Live demo
  • Desk lampHome$4912 in stock
  • Wireless keyboardTech$89Sold out
  • Notebook setOffice$1540 in stock
  • HeadphonesTech$1295 in stock

Props

PropTypeDescription
items T[] Data.
itemTemplate (item, layout, index) => ReactNode How each item looks.
label string Accessible name (required).
layout / showLayoutToggle 'list' | 'grid' / boolean Current layout and toggle.
paginator / rows boolean / number Paging.
sortField / sortOrder string / 1 | -1 Sorting.

Accessibility

DataView keyboard support
KeyAction
Tab Moves through the layout toggle, items and paginator

Code

ReactComing to Vue, Svelte and Angular.

DataView · React
<DataView label="Products" items={products} showLayoutToggle paginator rows={4}
  itemTemplate={(p, layout) => <ProductCard product={p} compact={layout === 'list'} />} />

Paginator Link to Paginator

Full paging control with rows-per-page, page report and jump-to-page.

Live demo

Showing: records 1–10 of 240

Props

PropTypeDescription
totalRecords number Total item count.
first / rows number Offset and page size.
onPageChange (state) => void { first, rows, page, pageCount }.
rowsPerPageOptions number[] Page-size dropdown.
showCurrentPageReport / showJumpToPage boolean Extra controls.

Accessibility

Paginator keyboard support
KeyAction
Tab Move between page buttons
Enter Go to the typed page number

A labelled navigation landmark; the current page button has aria-current="page".

Code

ReactComing to Vue, Svelte and Angular.

Paginator · React
<Paginator totalRecords={240} rows={rows} first={first}
  rowsPerPageOptions={[10, 20, 50]} showCurrentPageReport showJumpToPage
  onPageChange={(s) => { setFirst(s.first); setRows(s.rows); }} />

Pagination Link to Pagination

A compact page switcher with ellipsis for long ranges.

Live demo

Page: 5

Props

PropTypeDescription
value number Current page (1-based).
pageCount number Number of pages.
onChange (page) => void Called with the new page.

Accessibility

Pagination keyboard support
KeyAction
Tab Move between page links

Code

Pagination · React
<Pagination value={page} pageCount={12} onChange={setPage} />

VirtualScroller Link to VirtualScroller

Renders only the visible rows of very long lists, with optional lazy loading.

Live demo

10,000 rows — only the visible ones are in the DOM.

00001 · GET /api/items/0 — 200
00002 · GET /api/items/919 — 300
00003 · GET /api/items/838 — 400
00004 · GET /api/items/757 — 200
00005 · GET /api/items/676 — 300
00006 · GET /api/items/595 — 400
00007 · GET /api/items/514 — 200
00008 · GET /api/items/433 — 300
00009 · GET /api/items/352 — 400
00010 · GET /api/items/271 — 200
00011 · GET /api/items/190 — 300

Props

PropTypeDescription
items Array<T | undefined> Data (undefined = not loaded yet).
itemTemplate (item, index) => ReactNode Row renderer.
itemSize / height number / number | string Row height and viewport height.
onLazyLoad ({ first, last }) => void Fetch the visible range.
label string Accessible name (required).

Accessibility

VirtualScroller keyboard support
KeyAction
Arrow Down / Arrow Up Move the active row
Home / End First / last row

Rows carry aria-setsize and aria-posinset, so the real list length is announced even though few rows exist in the DOM.

Code

ReactComing to Vue, Svelte and Angular.

VirtualScroller · React
<VirtualScroller label="Log lines" items={lines} itemSize={36} height={280}
  itemTemplate={(line, i) => <span>{i + 1}. {line}</span>} />

OrderList Link to OrderList

Reorder a list with buttons or the keyboard.

Live demo
Priorities
  • Fix login bug
  • Ship dark mode
  • Write release notes
  • Update dependencies
  • Plan Q3 roadmap

Use Alt with arrow keys, Home or End to move the selected item.

Order: Fix login bug → Ship dark mode → Write release notes → Update dependencies → Plan Q3 roadmap

Props

PropTypeDescription
value / onChange T[] Items in order.
getKey / getLabel (item) => Key / string Identity and announced name.
header string List title (required).
itemTemplate (item) => ReactNode Custom row.

Accessibility

OrderList keyboard support
KeyAction
Arrow Down / Arrow Up Move focus
Space / Enter Select the focused item
Alt + Arrow Up / Alt + Arrow Down Move the selected item up / down
Alt + Home / Alt + End Move it to the top / bottom

Every move is announced ("Moved Design to position 2 of 5").

Code

ReactComing to Vue, Svelte and Angular.

OrderList · React
<OrderList header="Priorities" value={items} onChange={setItems}
  getKey={(i) => i.id} getLabel={(i) => i.name} />

PickList Link to PickList

Move items between two lists — available and selected.

Live demo
Available (6)
  • Lina
  • Omar
  • Sara
  • Yousef
  • Maya
  • Adam
On the team (1)
  • Noor

Team: Noor

Props

PropTypeDescription
value / onChange { source: T[]; target: T[] } Both lists.
getKey / getLabel (item) => Key / string Identity and announced name.
sourceHeader / targetHeader string List titles.

Accessibility

PickList keyboard support
KeyAction
Arrow Down / Arrow Up Move focus within a list
Enter / Space Select the focused item
Tab Reach the transfer buttons

Code

ReactComing to Vue, Svelte and Angular.

PickList · React
<PickList value={lists} onChange={setLists} getKey={(p) => p.id} getLabel={(p) => p.name}
  sourceHeader="Available" targetHeader="On the team" />

OrganizationChart Link to OrganizationChart

A top-down tree for org charts and hierarchies, with selection and collapsing.

Live demo

Selected: none

Props

PropTypeDescription
value OrgChartNode Root { key, label, children? }.
label string Accessible name (required).
selectionMode 'single' | 'multiple' Selectable nodes.
collapsible boolean Allow hiding branches.
nodeTemplate (node) => ReactNode Custom node card.

Accessibility

OrganizationChart keyboard support
KeyAction
Arrow keys Move between parent, children and siblings
Enter / Space Select the node

Code

ReactComing to Vue, Svelte and Angular.

OrganizationChart · React
<OrganizationChart label="Company structure" collapsible selectionMode="single"
  value={{ key: 'ceo', label: 'CEO', children: [{ key: 'cto', label: 'CTO' }, { key: 'cfo', label: 'CFO' }] }} />

Timeline Link to Timeline

Events in vertical, horizontal or alternating layouts, with status markers, icons or avatars, relative times, date groups, expandable details and a progress connector.

The rich options (layouts, dates, details) are React-only for now; other frameworks render the classic vertical timeline.

Live demo

Yesterday

  1. (Oct 15, 2026, 6:12 PM)
    Order placed (completed)
    3 items · $128.00
  2. (Oct 15, 2026, 7:12 PM)
    Payment confirmed (completed)

Today

  1. (Oct 16, 2026, 6:12 PM)
    Lina Haddad: Shipped from Amman (current)
    Packed by Lina
  2. Out for delivery

Props

PropTypeDescription
items TimelineItem[] { title, description?, time?, date?, status?, variant?, icon?, avatar?, details?, meta? }.
layout 'vertical' | 'horizontal' | 'alternate' Horizontal and alternate fall back to vertical in narrow containers.
relative / locale / now boolean / string / Date "2h ago" labels with the full date in the tooltip.
groupBy 'day' | 'month' | (item) => string Date headings (Today, Yesterday…).
loading boolean Skeleton while data loads.
reveal boolean Fade items in on scroll (off with reduced motion).

Accessibility

Timeline keyboard support
KeyAction
Enter / Space Show or hide the details of an item (on its toggle)

Ordered lists (one per date group, labelled by its heading). Status is also spoken ("completed", aria-current for the current step); relative times include the absolute date for screen readers; markers are decorative.

Code

Timeline · React
<Timeline relative groupBy="day" items={[
  { title: 'Order placed', date: placedAt, status: 'complete', icon: <CartIcon /> },
  { title: 'Shipped', date: shippedAt, status: 'current', details: <Tracking id="1Z999" /> },
  { title: 'Delivered', status: 'upcoming' },
]} />

Search Pelagic UI