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 — Page controls. DataTable renders Pagination when page is set with a total, or when client paging slices rows.
  • 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 next to @bridge-ui/vue. The public API stays columns / rows / sorting — the table engine is not exported.

Note

Install @tanstack/react-table 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 and bind sorting so header clicks cycle unsorted → ascending → descending. Cell text defaults to row[id] (or accessor) when no renderer is set.

Variants

Chrome matches Table: plain (default), ghost, or bordered. Built-in Pagination follows the pairing unless slots.pagination overrides it.

DataTable variant Pagination variant
plain text
ghost ghost
bordered outlined

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

Pagination

Built-in Pagination when page is set with pageCount or totalCount (server fetch stays in the app). page + perPage without those totals slices rows locally. perPage also renders a Select (perPageOptions, default 10 / 25 / 50 / 100).

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. With perPage, the per-page Select and pager sit on opposite ends when they fit on one row of the bar; they stack and center when they overflow. Without perPage, the pager aligns to the end. Replace the controls with 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.

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. 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

Pass search and/or onSearchChange to show a search field in the toolbar. Client-side tables filter visible columns; 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

Pass hiddenColumns and/or onHiddenColumnsChange to show a Columns icon in the toolbar. 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 show a default empty state; 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 pagination.

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.

Table, Pagination, List, Select, Menu

Accessibility

  • DataTable keeps a real table with thead / tbody / optional tfoot.
  • Sortable headers set aria-sort (none / ascending / descending).
  • Selection checkboxes and radios are named Select row and Select all rows.
  • Filter, Columns, and Search 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 row, optional bar loading -->
        <tbody> <!-- data rows, expand rows, empty state -->
        <tfoot> <!-- summary -->
    <div> <!-- slots.footer -->
    <div> <!-- per-page Select + Pagination -->
</div>

Use classes for root, toolbar, wrapper, table, header, body, row, head, cell, empty, loading, footer, search, 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, Pagination, 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 pagination / per-page follow 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 built-in Pagination. 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.
size TableSize "md" Cell padding and type scale: sm, md, lg.
slots DataTableSlots empty, expanded, footer, item, loading, pagination, perPage, search, 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. Built-in Pagination follows the matching 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.
sortable boolean Whether the column can be sorted.
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.