Appearance
DataTable
A table for displaying columnar data. Accepts a plain record of arrays or a ModelOutput from a simulation.
Examples
Basic usage
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
susceptible: [1000, 980, 945, 900, 860],
infected: [1, 21, 56, 101, 141],
}"
/>Column labels and width
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
susceptible: [1000, 980, 945, 900, 860],
infected: [1, 21, 56, 101, 141],
}"
:column-config="{
day: { label: 'Day', width: 'small' },
susceptible: { label: 'Susceptible' },
infected: { label: 'Infected' },
}"
/>Formatting cell values
Use format on a column to override the default rendering. Accepts a {@link NumberFormat} value — a preset name (optionally with :N digits, e.g. "percent:1"), a printf-style format string, or a function (value, row) => string. Formatted values are also used in CSV exports.
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
rate: [0.012, 0.234, 0.467, 0.512, 0.601],
cases: [1, 21, 56, 101, 141],
}"
:column-config="{
day: { label: 'Day', width: 'small' },
rate: { label: 'Attack rate', format: 'percent:1' },
cases: { label: 'Cases', format: '%05d' },
}"
/>Cell class and max rows
vue
<DataTable
:data="{
generation: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
cases: [1, 3, 8, 15, 28, 45, 62, 71, 55, 30],
}"
:max-rows="5"
:column-config="{
generation: { label: 'Gen', cellClass: 'text-secondary', width: 50 },
cases: { label: 'Cases' },
}"
/>Wrapping long content
By default, cell content stays on one line and truncates with an ellipsis when it's wider than the column — so a long string in one column can't spill into the next. Set wrap: true on a column to let it grow vertically instead.
vue
<DataTable
:data="{
drug: ['Compound A', 'Compound B', 'Compound C'],
note: [
'Well tolerated at all tested doses; no adverse events reported.',
'Mild GI symptoms in 4% of participants; resolved without intervention.',
'Discontinued at week 6 after liver-enzyme elevation in two participants.',
],
}"
:column-config="{
drug: { width: 'small' },
note: { wrap: true, width: 'large' },
}"
/>Use columnClass to attach a class to both the header and every body cell in a column — handy when whole-column styling (background, border, font weight) should match across the header and data. cellClass keeps its meaning (body cells only).
Full width
By default the table sizes to its content (columns default to a fixed medium width, so they're evenly spaced). Pass full-width to stretch the table to fill its container; columns without an explicit width will share the available space equally.
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
susceptible: [1000, 980, 945, 900, 860],
infected: [1, 21, 56, 101, 141],
}"
full-width
/>Download menu
A ⋯ menu appears in the top-right corner of every table with a Download item that exports the data as CSV. Use download-menu-link to customize the menu item label and filename to control the downloaded filename. Pass :menu="false" to hide the menu entirely.
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
cases: [1, 21, 56, 101, 141],
}"
filename="sir-cases"
download-menu-link="Download cases (CSV)"
/>Custom CSV download
By default, the Download menu item exports the displayed table as CSV. Use the csv prop to supply your own content — for example, to include ISO dates, extra columns that aren't in the table, or values formatted differently from the on-screen rendering. Accepts a raw string or a function returning one (called lazily on click).
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
cases: [1, 21, 56, 101, 141],
}"
filename="sir-cases"
:csv="`date,day,cases
2024-01-01,0,1
2024-01-02,1,21
2024-01-03,2,56
2024-01-04,3,101
2024-01-05,4,141`"
/>Download button
Pass download-button to render a visible, labeled button beneath the table instead of exposing the download only via the top-right menu. The button uses download-menu-link as its label, and the menu's Download item is suppressed so the action isn't duplicated. The button has the class data-table-download-button and its styles are unscoped, so it can be targeted directly from custom CSS without specificity battles.
| day | cases |
|---|---|
| 0 | 1 |
| 1 | 21 |
| 2 | 56 |
| 3 | 101 |
| 4 | 141 |
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
cases: [1, 21, 56, 101, 141],
}"
filename="sir-cases"
download-menu-link="Download CSV"
download-button
:csv="`date,day,cases
2024-01-01,0,1
2024-01-02,1,21
2024-01-03,2,56
2024-01-04,3,101
2024-01-05,4,141`"
/>Download link
Pass download-link to render a plain text link beneath the table instead of (or alongside) the menu. It's a real <a href download> — right-click → Save As works. Pass true for the default "Download data (CSV)" label, or a string to customize. The menu's Download item is suppressed when this is set. If both download-link and download-button are set, the button wins.
| day | cases |
|---|---|
| 0 | 1 |
| 1 | 21 |
| 2 | 56 |
| 3 | 101 |
| 4 | 141 |
vue
<DataTable
:data="{
day: [0, 1, 2, 3, 4],
cases: [1, 21, 56, 101, 141],
}"
filename="sir-cases"
download-link
/>Props
| Prop | Type | Required | Default |
|---|---|---|---|
data | TableData | Yes | — |
maxRows | number | No | — |
columnConfig | Record<string, ColumnConfig> | No | — |
menu | boolean | string | No | true |
csv | string | (() => string) | No | — |
filename | string | No | — |
downloadMenuLink | string | No | "Download" |
downloadButton | boolean | No | false |
downloadLink | boolean | string | No | — |
fullWidth | boolean | No | false |
ColumnConfig
ts
interface ColumnConfig {
label?: string;
width?: "small" | "medium" | "large" | number;
align?: "left" | "center" | "right";
/** Class applied to body `<td>` cells only. */
cellClass?: string;
/** Class applied to both the header `<th>` and body `<td>` cells. */
columnClass?: string;
/** Allow cell contents to wrap. Default `false` (nowrap + ellipsis). */
wrap?: boolean;
format?: NumberFormat | ((value: CellValue, row: number) => string);
}
type CellValue = number | string | boolean;
type NumberFormat =
| NumberFormatPreset // "plain" | "localized" | "percent" | "compact" | "scientific" | "engineering" (optionally with ":N" digits, e.g. "percent:1")
| string // printf-style format, e.g. "%.2f", "%05d"
| ((value: number) => string);See formatNumber in @cfasim-ui/shared for the underlying utility — you can also call it directly in your own code.