Bridge UI

DataTable

Opinionated data grid with sort, selection, filters, and pagination.

Introduction

DataTable is an opinionated grid for columns and rows: sorting, selection, filters, search, empty and loading states, and pagination wiring. It composes Table for layout, sticky header, and column alignment. size, variant, full, striped, hoverable, and rounded are forwarded to Table.

When to use: Interactive datasets where the app owns fetch and DataTable owns chrome. Use Table for static markup you compose yourself.

Compared to similar components:

  • Table — Presentational primitives (table / thead / tbody). No sort, selection, or pager.
  • Pagination — Numbered page controls. DataTable renders its own chrome footer (selection summary, per-page Select, first / previous / next / last) instead of Pagination.
  • List — A vertical index of items. Use List for navigation rows; use DataTable when values line up across columns and need grid chrome.

Use the framework selector in the site header to switch between React and Vue.

Note

Install @tanstack/vue-table v9 next to @bridge-ui/vue. The public API stays columns / rows / sorting — the table engine is not exported.

Note

Install @tanstack/react-table v9 next to @bridge-ui/react. The public API stays columns / rows / sorting — the table engine is not exported.

Import

import { DataTable } from "@bridge-ui/vue/Components/DataTable";
import { DataTable } from "@bridge-ui/react/Components/DataTable";

Basic usage

Pass columns and rows. Set sortable on a column to show a sort button in that header. Cell text defaults to row[id] (or accessor) when no renderer is set.

Sorting

Set sortable on a column to show a sort button in that header, matching the filter control. Clicks cycle unsorted → ascending → descending → unsorted. Bind sorting and onSortingChange (React) or v-model:sorting (Vue). The header cell keeps aria-sort; clicking the column title does not sort.

Client-side tables still sort the current rows when sorting is unbound. Bind it to control sort, or to send it with a server fetch when page and a total are set.

Variants

Chrome matches Table: plain (default), ghost, or bordered. The built-in footer pager is first / previous / next / last and does not follow table variant.

striped and hoverable are independent of variant. full={false} sizes columns to content; the bordered wrapper and chrome footer follow that width. stickyHeader pins header cells to the page; "boxed" pins them inside the wrapper — set a max height on classes.wrapper.

Pagination

The chrome footer shows a selection summary when selection is bound, a per-page Select when perPage is set (perPageOptions, default 10 / 25 / 50 / 100), and a first / previous / next / last pager when page is set with pageCount or totalCount (server fetch stays in the app). page + perPage without those totals slices rows locally.

When page and a total are set, DataTable does not sort or filter rows locally — bind sorting / filters / page and fetch the current page in the app. The pager also shows Page {{page}} of {{count}}. Replace the footer controls with slots.selected, slots.pagination, and slots.perPage.

Selection

Pass selection (always string[]) and getRowId. selectionMode="multiple" (default) uses checkboxes and select-all. selectionMode="single" uses radios and keeps at most one id. Binding selection also shows a chrome-footer summary ({{selected}} of {{total}} row(s) selected.).

Filters

Set filters on a column to show a funnel in that header. The panel uses checkboxes (filterMultiple, default) or radios (filterMultiple={false}), and Select all items for multiple filters. Nested children render as a group. OK commits; Reset clears the draft (commit on OK); closing without OK discards it.

Set searchable on a column to add a text field in that same overlay, and to include the column in the toolbar search. Queries live in columnSearch (column id → string) and filter rows — they do not filter the option list. Hidden columns skip their column-search queries.

Column filters open in a FieldOverlay. Default filterOverlay is auto (menu on desktop, drawer on mobile). Pass menu, modal, or drawer to pin a shell.

Search and toolbar

The toolbar search field is hidden by default. Pass showSearch to show it with internal state, or bind search when the app needs the query. Client-side tables filter columns with searchable; if none are set, every visible column is matched. Server-paged tables emit the query only.

slots.toolbar is the leading region. slots.toolbarActions sits in the end cluster beside Columns and Search. The toolbar shows when either slot is set, or when Columns / Search are enabled.

Sticky columns

sticky="start" or sticky="end" pins a column while the table scrolls horizontally. Selection and expand chrome pin to start when any data column uses sticky="start". Set width on pinned columns so offsets stay stable; pinned columns without a parseable width fall back to 120px. Keep those widths modest so other columns stay visible on small screens. Columns need enough width (or a constrained wrapper) so the table overflows and a horizontal scrollport appears.

Column classes

classes.header and classes.cell merge onto that column’s th / td (body and footer). Use width utilities for breakpoint-based sizing. Do not set width on the same column when the class should control width — inline width wins.

Column visibility

The toolbar Columns icon is hidden by default. Pass showColumnVisibility to show it with internal state, or bind hiddenColumns when the app needs the ids. hideable={false} keeps a column out of the toggle (or disabled). At least one column stays visible.

The panel opens in a FieldOverlay. Default columnsOverlay is auto (menu on desktop, drawer on mobile). Pass menu, modal, or drawer to pin a shell.

When unset, columnsShowFooter is true for modal / drawer (false for menu). Reset restores hideable columns; OK commits and closes. Closing without OK discards the draft.

Expand

Controlled expanded row ids. slots.expanded renders in a spanning row under the data row.

Empty rows render EmptyState at the table size, with the semantic inbox icon and the i18n title "No data". slots.empty replaces it. loading keeps the table visible. loadingVariant="overlay" (default) dims the table with a spin; loadingVariant="bar" dims the table and draws a progress line under the header. slots.loading replaces the indicator. slots.footer renders below the table, above the chrome footer.

Item slots

cell on a column is for portable renderers. An item slot wins: React slots.item.{id}, Vue #item.{id}.

Summary

Set summary on a column to render a footer row over the current (filtered) rows. Chrome cells stay empty. Set ellipsis on a column to truncate overflowing cell text; the tooltip uses the column accessor. When any column sets ellipsis, the table switches to a fixed layout at full width, so give columns a width when they should not share space evenly.

Table, Pagination, List, Select, Menu, EmptyState

Accessibility

  • DataTable keeps a real table with thead / tbody / optional tfoot.
  • Sortable headers set aria-sort (none / ascending / descending).
  • The sort control is a header button named "Sort ascending", "Sort descending", or "Cancel sorting".
  • Selection checkboxes and radios are named Select row and Select all rows.
  • Filter, Columns, Search, and Sort controls are named buttons/fields. Expand uses Expand row.
  • loading sets aria-busy on the table.

Anatomy

<div> <!-- DataTable root -->
  <div> <!-- toolbar: slots.toolbar, Columns, slots.toolbarActions, Search -->
  <div> <!-- frame: hugs table when full is false -->
    <div> <!-- table + loading overlay -->
      <table> <!-- Table -->
        <thead> <!-- header: label, sort button, filter; optional bar loading -->
        <tbody> <!-- data rows, expand rows, empty state -->
        <tfoot> <!-- summary -->
    <div> <!-- slots.footer -->
    <div> <!-- chrome footer: selection summary, per-page Select, page status, first / previous / next / last -->
</div>

Use classes for root, toolbar, wrapper, table, header, body, row, head, cell, empty, loading, footer, search, selected, pagination, and perPage. Each column also accepts classes.header and classes.cell.

API

Bindings

Prop / event Type Description
v-model:column-search DataTableColumnSearch Column id → text query.
v-model:expanded string[] Expanded row ids.
v-model:filters DataTableFilters Column id → selected option values.
v-model:hidden-columns string[] Hidden column ids.
v-model:page number 1-based page.
v-model:per-page number Page size.
v-model:search string Toolbar search query.
v-model:selection string[] Selected row ids.
v-model:sorting DataTableSorting Controlled sort, or null when unsorted.

Bindings

Prop Type Description
columnSearch DataTableColumnSearch Column id → text query.
expanded string[] Expanded row ids.
filters DataTableFilters Column id → selected option values.
hiddenColumns string[] Hidden column ids.
onColumnSearchChange (search) => void Called when column search changes.
onExpandedChange (ids: string[]) => void Called when expanded ids change.
onFiltersChange (filters) => void Called when filters change.
onHiddenColumnsChange (ids: string[]) => void Called when visibility changes.
onPageChange (page: number) => void Called when the page changes.
onPerPageChange (perPage: number) => void Called when page size changes (also resets to page 1).
onSearchChange (query: string) => void Called when toolbar search changes.
onSelectionChange (ids: string[]) => void Called when selection changes.
onSortingChange (sorting) => void Called when sort changes.
page number 1-based page.
perPage number Page size.
search string Toolbar search query.
selection string[] Selected row ids.
sorting DataTableSorting Controlled sort, or null when unsorted.

DataTable

Prop Type Default Description
classes DataTableClasses — Classes for root, toolbar, table wrapper, and descendant parts.
columns DataTableColumn[] [] Column definitions.
columnsOverlay FieldOverlayMode "auto" Overlay shell for the Columns panel: menu, modal, drawer, or auto.
columnsShowFooter boolean — Reset / OK on the Columns overlay. Unset: true for modal / drawer, false for menu. Draft until OK.
customProps DataTableCustomProps — Extra props for table parts, selection controls, chrome pager, per-page Select, search field, and progress.
filterOverlay FieldOverlayMode "auto" Overlay shell for column filter panels: menu, modal, drawer, or auto.
full boolean true Stretch the table to at least the wrapper width. When false, the wrapper hugs column content, and the chrome footer follows that width.
getRowId (row: T) => string — Stable row id. Required for reliable selection and expand.
hoverable boolean false Row hover styles on the body.
loading boolean false Show the loading region (aria-busy on the table).
loadingVariant "overlay" \| "bar" "overlay" Overlay spin, or a progress line under the header. Both dim the table.
pageCount number — Total pages for the built-in chrome pager. Use this or totalCount.
perPageOptions number[] [10, 25, 50, 100] Options for the built-in per-page Select.
rounded TableRounded "lg" Corner radius of the wrapper, header, and footer.
rows T[] [] Current page of data, or the full set when not server-paging.
selectionMode "single" \| "multiple" "multiple" Radios or checkboxes.
showColumnVisibility boolean false Show the toolbar Columns control with internal hidden-column state. Bind hiddenColumns when the app needs the ids.
showSearch boolean false Show the toolbar search field with internal query state. Bind search when the app needs the query.
size TableSize "md" Cell padding and type scale: sm, md, lg.
slots DataTableSlots — empty, expanded, footer, item, loading, pagination, perPage, search, selected, toolbar, toolbarActions.
stickyHeader boolean \| 'boxed' false Pin headers to the page, or inside the wrapper when "boxed".
striped boolean false Alternating body row surfaces.
totalCount number — Total item count; derives page count with perPage. pageCount wins if both are set.
variant TableVariant "plain" Chrome forwarded to Table. The built-in footer pager does not follow table variant.

Column

Field Type Default Description
accessor (row: T) => unknown row[id] Value used for client-side sorting, filtering, search, and ellipsis tooltips.
align TableAlign "start" Text alignment for the header and cells.
cell (row: T) => ReactNode accessor / row[id] Portable cell renderer. Item slots win.
classes DataTableColumnClasses — Extra classes for this column: header on the th, cell on body and footer td.
ellipsis boolean false Truncate overflowing cell text and show the full value in a tooltip.
filterMultiple boolean true When false, the filter overlay allows only one value.
filters DataTableFilterOption[] — Filter overlay options. Presence enables the header funnel.
header ReactNode — Header content.
hideable boolean true When false, the column cannot be toggled in the Columns overlay.
id string — Stable column id (also the default accessor key).
searchable boolean false Adds a text field in that header’s filter overlay, and includes the column in the toolbar search.
sortable boolean — Shows a sort button in the header. Clicks cycle unsorted → ascending → descending → unsorted.
sticky "start" \| "end" — Pin the column while the table scrolls horizontally.
summary (rows: T[]) => ReactNode — Footer cell for a summary row over the current (filtered) rows.
width number \| string — Column width (px number or CSS length). Wins over class width when both are set.