Customization
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:
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:
DataTablepasses them on to the headers.DataTableToolbarpasses them on to Clear filters, Columns and the selection bar.DataTableSearchis one of the toolbar's children, so give itmessagesyourself.- 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:
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.
| Group | Texts for |
|---|---|
states | empty, error, loading |
actions | reload, clearFilters, retry |
search | the search box: label (for screen readers), placeholder, clear |
pagination | rowsPerPage, first, previous, next, last, morePages, and label for the nav |
selection | selectAll, selectRow, clear |
columns | the Columns menu: menu, pinStart, pinEnd, unpin, color, noColor, customColor, fitContent, fitAll, resetLayout, options(column) |
colors | the preset color names: red, orange, amber, green, teal, blue, violet, pink |
header | header controls, move(column) and resize(column), and what screen readers hear while a column moves |
counts | functions: number(value), page(page, pageCount), selected(selected, total), rows(count) |
sorting | asc, desc, clear, for your own sort controls (the built-in headers don't use them) |
editing | inline 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:
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:
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:
| File | What it holds |
|---|---|
data-table.tsx | The scroll area, the table and the sticky header. |
data-table-body.tsx | Rows, skeleton rows, and the empty and error states. |
data-table-cell-classes.ts | Cell styles: pinned backgrounds, the pinned edge's shadow, the column color tint, the header border. |
column-color-palette.ts | The 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:
/* Line up the digits in the amount column */
[data-slot="data-table"] td[data-column-id="amount"] {
font-variant-numeric: tabular-nums;
}| Attribute | On | Meaning |
|---|---|---|
data-slot | each part | data-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-id | header and body cells | the column's id |
data-state="selected" | rows | the row is selected |
data-pinned, data-pinned-edge | cells | start or end; the edge one is the innermost pinned column on that side |
data-scroll-start, data-scroll-end | data-table | columns are scrolled out of view on that side, so the pinned edge shows a shadow |
data-dragging, data-resizing | header and body cells, resize handles | while 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
Popoverfor the Columns list andDropdownMenufor the column menu. - React Aria uses
react-aria-components, and its buttons takeonPressinstead ofonClick. Its Columns popover is modal, so the rest of the page is hidden from screen readers while it's open.