Components Charts & data
Data Table
Present a compact set of structured records with typed cells, clear column labels, and an optional summary footer.
On this page
Examples
The project-progress seed: two fictional projects with percentages and labeled statuses. The 420 px table gives the project column extra room.
Preview setting only: fitting scales the whole table. Actual size preserves its authored width and content-derived height inside a scrolling region.
Preview only: surrounding canvas and spacing. All metrics are illustrative.
'use client';
import { DataTable } from '@coreux/ui';
export default function Default() {
return (
<div style={{ width: 420, background: '#F4F1E9' }}>
<DataTable
width={420}
ariaLabel="Illustrative project progress snapshot. These are fictional projects and completion rates."
columns={[
{ id: 'name', label: 'Project', type: 'text', weight: 1.5 },
{ id: 'progress', label: 'Progress', type: 'number' },
{ id: 'status', label: 'Status', type: 'status' },
]}
rows={[
{ id: 'r1', cells: {
name: { type: 'text', value: 'Customer Portal' },
progress: { type: 'number', value: 0.82, format: 'percent' },
status: { type: 'status', label: 'On track', tone: 'positive' },
} },
{ id: 'r2', cells: {
name: { type: 'text', value: 'CRM Modernization' },
progress: { type: 'number', value: 0.61, format: 'percent' },
status: { type: 'status', label: 'At risk', tone: 'warning' },
} },
]}
/>
</div>
);
}
Choosing a table
Use DataTable for a small, fixed composition where exact records matter: a project snapshot, an operations summary or a concise comparison. Use BarChart for relative magnitudes and LineChart for an ordered trend. This table presents supplied data; it does not provide sorting, filtering, pagination, selection or editing.
- Default retains both seed projects, their completion rates and status labels at 420 px wide. The project column receives extra relative width to keep its names readable.
- With footer retains the seed’s illustrative $2,400,000 annual savings figure and matching total at 420 px wide. A footer is supplied data, not an automatic aggregation.
- Typed cells & formats shows text, number, icon and status cells, all four number formats, and neutral, positive, warning and error statuses. Each mixed measure names its own unit.
- Eight rows & geometry reaches the six-column and eight-record limits, plus a separate footer. Its copied file computes totals from all eight illustrative records and reserves height with the public geometry helper.
- Presentation states · dark emphasizes a row and shows completed numeric and status changes. The snapshot is static; there is no internal animation clock or user interaction.
Both seeds keep their data and table dimensions. Unsupported seed-only format and currency column fields are removed: those settings belong to number cells and were already present there. Outer 24 px seed padding is supplied by the documentation canvas; copied files retain the matching background and descriptive table label. All figures and people in these examples are illustrative.
Cells & validation
Provide 2–6 columns and 1–8 records. The optional footer is additional to that record limit. Column IDs must be unique; record and footer IDs must also be unique together. IDs, column labels, text-cell values, icon labels, status labels and ariaLabel must each be one non-empty text line. There is no enforced character-count maximum, so test the actual content at the intended width.
Every row’s cells object must have exactly one key for each column ID and no unknown keys. Every cell’s type must match its column’s type, including footer cells. Missing cells, mismatched types, duplicate IDs, unsupported enum values and invalid dimensions throw during rendering. TypeScript’s record type cannot prove these relationships; validate any external data before rendering.
Cell types and number formatting
| Type | Required content | Behavior |
|---|---|---|
| text | Single-line value | Plain text; no arbitrary child content. Default alignment is start. |
| number | Finite numeric value | Zero and negative numbers are accepted. Per-cell formatting uses Intl.NumberFormat("en-US"); default alignment is end. |
| icon | One content item and single-line label | A clipped 30 × 30 px frame, centered by default. Supply one meaningful icon element with its own accessible name. |
| status | Single-line label and a tone | Choose neutral, positive, warning or error. The visible label explains the semantic status; default alignment is start. |
Number format resolves to decimal when omitted, with one decimal place. integer rounds to zero decimal places. percent multiplies the input by 100, so 0.82 becomes 82%; it does not enforce a 0–1 data range. currency requires an exactly three-letter uppercase code such as USD, and a currency code with another format throws. Choose a real currency code; the validator checks its shape rather than membership in an ISO list.
fractionDigits must be an integer from 0 to 4. It sets both minimum and maximum decimal places. Omission gives one place for decimal and zero for percent and currency, even for currencies normally shown with cents. Integer formatting always uses zero places, though any supplied fractionDigits must still pass validation. There is no locale prop and no column-level formatting.
Icon validation requires non-null, defined content and exactly one item according to React’s Children.count. It does not inspect whether that item renders a useful icon; a fragment counts as one even with several descendants. Use one actual SVG or image, keep it within the frame, and supply meaningful accessible text. The examples use standalone labeled SVGs without external assets.
Width & geometry
width is a required finite CSS-pixel number at least 360. There is no height prop: each record is 56 px tall, the optional header is 44 px, the optional footer is 56 px, and the outer border adds 4 px in total. Thus two records with a header are 160 px high; eight records, a header and a footer are 552 px high. Hiding the header removes 44 px but also removes the rendered column headings.
Column weight is a positive finite relative share, resolving to 1 when omitted. The available width is the outer width minus 4 px of border. For example, weights 2 and 1 allocate roughly two-thirds and one-third of that inner width. align overrides the type-based default with start, center or end for both the column header and its cells. There is no individual pixel-width, minimum-width, wrapping or density prop.
The public getDataTableGeometry helper accepts required width, columns and integer rowCount from 1 to 8, plus optional showHeader (true) and hasFooter (false). It applies the same width and column validation and returns total width/height, column x/width positions, row y/height positions, and nullable header/footer positions. It does not accept row contents or validate cells and footer IDs. Copy the dense example for a complete layout using the exported helper and types.
The 360 px minimum is a validity floor, not a promise that six columns will fit. Cells and headings use single-line clipped content with 16 px side padding. The status-change area alone needs at least 104 px before cell padding. Shorten labels, increase width or adjust weights after checking the output. Fit to canvas reduces the entire preview, including text; Actual size reveals the authored dimensions and supports contained horizontal scrolling.
Appearance & presentation states
fieldMode="light" uses an ivory table surface with a navy header; fieldMode="dark" reverses those surfaces and adjusts text, borders, footer and status colors. Status tones describe meaning rather than category order. Keep their explicit labels. The table uses inline styling and has no className, style, tone or arbitrary HTML-attribute passthrough.
Omitted rowProgress and footerProgress show the completed table. All progress values must be finite and clamp to 0–1; non-finite values throw. Row progress can be one scalar or an array exactly as long as the record list. It changes each row’s opacity and vertical offset, not the layout allocation or the accessible row count. Footer progress is separate and is validated even without a footer.
activeRow must reference an existing record and adds a cobalt emphasis overlay. valueChange must reference an existing number cell, with a finite fromValue, and interpolates toward that cell’s current value. statusChange must reference an existing status cell, with a valid previous label and tone, and crossfades to the current status. Each requires its own finite progress. None can target the footer; unknown row or column IDs and wrong target cell types throw.
These are presentation channels, not editing, selection or automatic change tracking. No timer, event handler or Remotion dependency is supplied. The dark example uses progress 1 to show the completed result. If a consumer animates intermediate values, respect reduced-motion preferences and keep a stable data explanation: transparent rows remain in the accessibility tree, and the current status label remains exposed while the old badge is always hidden from assistive technology.
Props
Types and required flags come from the installed public declarations. Top-level default values are checked against the implementation. Nested optional fields show undefined in the Default column; their resolved formatting and alignment behavior is described alongside each field. The four cell types together form DataTableCell.
| Prop / type | Default | Description |
|---|---|---|
widthRequirednumber | Required | Required finite width in CSS pixels, at least 360. Includes two 2 px borders. Height is derived from content; there is no height prop. |
columnsRequiredreadonly DataTableColumn[] | Required | 2–6 columns, each with a unique non-empty single-line ID, single-line label and supported cell type. Relative positive finite weights divide the inner width. |
rowsRequiredreadonly DataTableRow[] | Required | 1–8 records. Unique non-empty single-line IDs; exactly one cell per column ID with the matching type, and no unknown keys. |
showHeaderfalse | true | true | Shows the 44 px column-header row. False removes both its height and columnheader semantics; column definitions and validation still apply. |
footerRowDataTableRow | undefined | Optional additional summary row, outside the 1–8 record count. Must satisfy the same column and cell rules with a distinct ID. Adds 56 px; totals are supplied by the caller. |
fieldMode"light" | "dark" | "light" | light or dark selects surface, text, header, border and status appearance. Supply a matching surrounding surface. |
ariaLabelstring | "Structured records" | One non-empty text line naming the table. Include meaningful subject, units and timeframe; the default is generic. |
rowProgressnumber | readonly number[] | 1 | Finite scalar or exactly one number per record in row order; clamped to 0–1. Changes opacity and vertical reveal, without removing rows or their reserved height. |
activeRowDataTableActiveRow | undefined | Existing record ID and finite progress. Adds a cobalt emphasis overlay; it is not selection, focus or an interactive state. Cannot target the footer. |
valueChangeDataTableValueChange | undefined | Existing record and number-column IDs, finite fromValue and finite progress. Interpolates the displayed number toward the cell value. Cannot target a footer cell. |
statusChangeDataTableStatusChange | undefined | Existing record and status-column IDs, a valid previous label/tone and finite progress. Crossfades to the current status; the previous badge is aria-hidden. Cannot target the footer. |
footerProgressnumber | 1 | Finite scalar, clamped to 0–1, controlling footer opacity and vertical reveal. Validated even when no footer is provided. |
DataTableColumn
| Prop / type | Default | Description |
|---|---|---|
idRequiredstring | Required | Unique non-empty single-line string. Every row and footer must contain this exact cells key. |
labelRequiredstring | Required | Non-empty single-line column heading. Keep it short enough for the weighted column; long text is clipped. |
typeRequired"number" | "text" | "icon" | "status" | Required | text, number, icon or status. Every cell in this column must match, including the footer. |
align"start" | "center" | "end" | undefined | start, center or end. If omitted, numbers align end, icons center, and text/status start. Applies to header and cells. |
weightnumber | undefined | Finite number greater than zero; omitted weights resolve to 1. Relative share of inner width, not a pixel width or minimum. |
DataTableRow
| Prop / type | Default | Description |
|---|---|---|
idRequiredstring | Required | Unique non-empty single-line record ID. Footer IDs share the same uniqueness constraint. |
cellsRequiredReadonly<Record<string, DataTableCell>> | Required | Object keyed by column IDs. Exact column coverage is checked at render time; values are the discriminated DataTableCell union below. |
DataTableTextCell
| Prop / type | Default | Description |
|---|---|---|
typeRequired"text" | Required | Required discriminator: text. |
valueRequiredstring | Required | One non-empty text line. No character-count maximum is enforced; fit depends on column width. |
DataTableNumberCell
| Prop / type | Default | Description |
|---|---|---|
typeRequired"number" | Required | Required discriminator: number. |
valueRequirednumber | Required | Finite number; zero and negative values are accepted. Percent formatting multiplies the input by 100, so 0.82 displays as 82%. |
format"decimal" | "integer" | "percent" | "currency" | undefined | decimal, integer, percent or currency; resolves to decimal when omitted. Formatting belongs to the cell, not the column, and uses the en-US locale. |
currencystring | undefined | Required exactly three uppercase letters only when format is currency; supplying it with another format throws. Choose a real ISO currency code such as USD. |
fractionDigitsnumber | undefined | Optional integer from 0 to 4, used as both minimum and maximum decimal places. Omission resolves to 1 for decimal, 0 otherwise. Integer always renders 0 places even if this prop is supplied. |
DataTableIconCell
| Prop / type | Default | Description |
|---|---|---|
typeRequired"icon" | Required | Required discriminator: icon. |
contentRequiredReactNode | Required | Exactly one non-null React content item according to Children.count, inside a clipped 30 × 30 px frame. Use one actual icon element; a fragment can contain multiple descendants despite counting as one item. |
labelRequiredstring | Required | Required non-empty single-line accessible text, assigned to the icon wrapper span. Also give a meaningful SVG its own image role and accessible name. |
DataTableStatusCell
| Prop / type | Default | Description |
|---|---|---|
typeRequired"status" | Required | Required discriminator: status. |
labelRequiredstring | Required | Non-empty single-line visible status text. Keep the meaning explicit rather than relying on the dot color. |
toneRequired"neutral" | "positive" | "warning" | "error" | Required | Required neutral, positive, warning or error semantic appearance; do not use categorical accent names here. |
DataTableActiveRow
| Prop / type | Default | Description |
|---|---|---|
rowIdRequiredstring | Required | Must identify a record in rows, not footerRow. |
progressRequirednumber | Required | Required finite scalar, clamped to 0–1; controls the emphasis overlay strength. |
DataTableValueChange
| Prop / type | Default | Description |
|---|---|---|
rowIdRequiredstring | Required | Must identify a record in rows, not footerRow. |
columnIdRequiredstring | Required | Must identify an existing number cell in the target record. |
fromValueRequirednumber | Required | Finite previous value in the same unit as the cell; the current cell value supplies the destination. |
progressRequirednumber | Required | Required finite scalar, clamped to 0–1. Controls interpolation and a subtle 0.96–1 scale. |
DataTableStatusChange
| Prop / type | Default | Description |
|---|---|---|
rowIdRequiredstring | Required | Must identify a record in rows, not footerRow. |
columnIdRequiredstring | Required | Must identify an existing status cell in the target record. |
fromRequired{ readonly label: string; readonly tone: DataTableStatusTone; } | Required | Previous badge with a non-empty single-line label and neutral, positive, warning or error tone. It is hidden from assistive technology. |
progressRequirednumber | Required | Required finite scalar, clamped to 0–1. Crossfades old and current badges inside a minimum 104 × 28 px area. |
DataTableGeometry
| Prop / type | Default | Description |
|---|---|---|
widthRequirednumber | Required | Returned outer width in CSS pixels, including borders. |
heightRequirednumber | Required | Returned outer height: 4 + header height + 56 per record + optional 56 px footer. |
columnsRequiredreadonly { readonly id: string; readonly x: number; readonly width: number; }[] | Required | Column IDs with x offsets from the outer left edge and weighted widths in pixels. |
headerRequirednull | { readonly y: number; readonly height: number; } | Required | Header y offset and 44 px height, or null when showHeader is false. |
rowsRequiredreadonly { readonly index: number; readonly y: number; readonly height: number; }[] | Required | Zero-based record indices, y offsets and 56 px heights. The helper accepts only a record count, not record IDs or cells. |
footerRequirednull | { readonly y: number; readonly height: number; } | Required | Footer y offset and 56 px height, or null when hasFooter is false. |
Accessibility & layout
The component uses div elements with table, row, columnheader and cell roles, plus table row/column counts, record/footer row indices and cell column indices. Preserve those roles and keep the header visible when readers need its labels; this is a table, not an image or an interactive grid. Set a specific ariaLabel rather than accepting the generic “Structured records” default. Add a visible title, timeframe, source and takeaway beside a published table.
Each icon wrapper receives its label on a plain span, which alone does not guarantee an announced image name. The copied examples also name the SVG and give it an image role. Status badges keep visible text, so their meaning does not depend only on color. The component supplies no sort buttons, live announcements or keyboard cell navigation. Long text can be visually clipped despite remaining in the DOM; provide enough width for essential content.
The documentation keeps the complete table semantics inside a focusable scroll region. On a narrow screen, choose Actual size and use the arrow keys to inspect the fixed-width content. Fitting only scales the preview and never changes copied source. A consumer should provide equivalent overflow containment, or choose a simpler presentation with fewer columns; the component has no responsive breakpoints.
Consumer setup
Browsing, previews, and copying are public. Installing the private @coreux/ui package requires repository read access and permission to use the bundled CoreUX brand fonts.
Follow the one-time installation guide for the pinned Git dependency, Tailwind v4 stylesheet setup, fonts, and troubleshooting. Keep the 'use client' directive in each example; no provider is required.
The quick start walks through a copied StatBlock in a minimal app.
Source & revision
This reference targets @coreux/ui version 0.1.0 at 06f42fd. Types come from its installed declarations; explanations and defaults are checked against this implementation.
Revision and upgrade notes · Contribution and coverage guide
View DataTable source (repository access required)