Search documentation

Search for a page or heading...

tablecn
0

Translate the table UI and restyle it.

Translate the UI

Every text the table shows comes from a messages object. English is the default, and Vietnamese is included:

Vietnamese
import { viTableMessages } from "@querycn/table-react/locales/vi"

<DataTableToolbar table={table} messages={viTableMessages}>
  <DataTableSearch table={table} messages={viTableMessages} />
</DataTableToolbar>
<DataTable table={table} messages={viTableMessages} />
<DataTablePagination table={table} messages={viTableMessages} />

Pass messages to each component you render:

  • DataTable passes them on to the headers.
  • DataTableToolbar passes them on to Clear filters, Columns and the selection bar.
  • DataTableSearch is one of the toolbar's children, so give it messages yourself.
  • The selection column is part of your columns: createSelectionColumn<Order>(viTableMessages).

Column headers come from your column definitions, so translate them there. The filter has its own texts: see Filter customization.

Change a few texts

mergeTableMessages lets you list only what changes:

lib/table-messages.ts
import { enTableMessages, mergeTableMessages } from "@querycn/table-react"

export const tableMessages = mergeTableMessages(enTableMessages, {
  states: { empty: "No orders yet." },
  actions: { reload: "Refresh" },
  counts: { rows: (count) => `${count} orders` },
})

Define it outside your components, and pass it to every component.

GroupTexts for
statesempty, error, loading
actionsreload, clearFilters, retry
searchthe search box: label (for screen readers), placeholder, clear
paginationrowsPerPage, first, previous, next, last, morePages, and label for the nav
selectionselectAll, selectRow, clear
columnsthe Columns menu: menu, pinStart, pinEnd, unpin, color, noColor, customColor, fitContent, fitAll, resetLayout, options(column)
colorsthe preset color names: red, orange, amber, green, teal, blue, violet, pink
headerheader controls, move(column) and resize(column), and what screen readers hear while a column moves
countsfunctions: number(value), page(page, pageCount), selected(selected, total), rows(count)
sortingasc, desc, clear, for your own sort controls (the built-in headers don't use them)
editinginline editing: edit(column), saving, saveFailed, invalidNumber, search, noOptions, loadFailed

Numbers

The built-in locales format numbers for their language (1,234 in English, 1.234 in Vietnamese). To follow the user's browser instead:

Locale-aware numbers
const format = new Intl.NumberFormat(navigator.language).format

mergeTableMessages(enTableMessages, {
  counts: {
    number: format, // page buttons and page sizes
    rows: (count) => (count === 1 ? "1 row" : `${format(count)} rows`),
  },
})

In server mode, page(page, pageCount) gets pageCount as undefined until the total is known: write "Page 3" rather than "Page 3 of 12".

Another language

Write a full TableMessages object. TypeScript tells you every key that's missing. Start from a copy of packages/table-react/src/locales/en.ts:

lib/table-messages-fr.ts
import type { TableMessages } from "@querycn/table-react"

export const frTableMessages: TableMessages = {
  states: { empty: "Aucun résultat.", error: "Une erreur est survenue.", loading: "Chargement…" },
  // …every other group
}

Restyle

The table UI is source code in your project, so you can change anything. Good places to start:

FileWhat it holds
data-table.tsxThe scroll area, the table and the sticky header.
data-table-body.tsxRows, skeleton rows, and the empty and error states.
data-table-cell-classes.tsCell styles: pinned backgrounds, the pinned edge's shadow, the column color tint, the header border.
column-color-palette.tsThe preset colors, and which custom colors are accepted.

For per-row styles, pass rowClassName to DataTable. For a cell's content, render what you need in the column's cell.

Style with data attributes

You can also style from your CSS, using the data-* attributes the components set:

globals.css
/* Line up the digits in the amount column */
[data-slot="data-table"] td[data-column-id="amount"] {
  font-variant-numeric: tabular-nums;
}
AttributeOnMeaning
data-sloteach partdata-table (the scroll area), data-table-toolbar, data-table-selection-bar, data-table-pagination, data-table-resize-handle, data-table-guide-line (the line showing where a moved or resized column lands), data-table-editable-cell (a cell users can edit)
data-column-idheader and body cellsthe column's id
data-state="selected"rowsthe row is selected
data-pinned, data-pinned-edgecellsstart or end; the edge one is the innermost pinned column on that side
data-scroll-start, data-scroll-enddata-tablecolumns are scrolled out of view on that side, so the pinned edge shows a shadow
data-dragging, data-resizingheader and body cells, resize handleswhile a column moves (its header and cells) or resizes

Radix UI, Base UI or React Aria

The three versions have the same files, so the same changes apply. They only differ in the primitives underneath:

  • Radix UI and Base UI use your shadcn Popover for the Columns list and DropdownMenu for the column menu.
  • React Aria uses react-aria-components, and its buttons take onPress instead of onClick. Its Columns popover is modal, so the rest of the page is hidden from screen readers while it's open.