UiTable

A data table with a built-in comparison mode.

Contents

A general, accessible data table driven by columns and rows: each column names a key, and each row is an object keyed by those keys. It renders a real <table> (caption, scope headers) that scrolls horizontally on narrow screens rather than crushing its columns. Comparison is a configuration rather than a separate component — mark the label column header, give the featured column highlight, and hand each value column an icon — which reproduces the old comparison table. The #cell scoped slot takes over any cell.

Examples

Data table

Columns name a key; rows are objects keyed by those keys. Align a column right.

Team
NameRoleCommits
Ada Lovelace Engineer 128
Grace Hopper Lead 342
<UiTable
  caption="Team"
  :columns="[
    { key: 'name', label: 'Name' },
    { key: 'role', label: 'Role' },
    { key: 'commits', label: 'Commits', align: 'right' },
  ]"
  :rows="[
    { key: 'ada', name: 'Ada Lovelace', role: 'Engineer', commits: 128 },
    { key: 'grace', name: 'Grace Hopper', role: 'Lead', commits: 342 },
  ]"
/>

Comparison mode

Mark the label column header, the featured column highlight, and give each value column an icon — the old comparison table as a configuration.

How Numori compares
FeatureNumoriThe usual suite
Open source The whole ecosystem The client, sometimes
Sync End-to-end encrypted Readable on the server
AI training Never On by default
<UiTable
  caption="How Numori compares"
  hide-caption
  :columns="[
    { key: 'feature', label: 'Feature', header: true },
    { key: 'numori', label: 'Numori', highlight: true, icon: 'mdi:check-circle' },
    { key: 'usual', label: 'The usual suite', icon: 'mdi:minus-circle-outline' },
  ]"
  :rows="[
    { key: 'oss', feature: 'Open source', numori: 'The whole ecosystem', usual: 'The client, sometimes' },
    { key: 'sync', feature: 'Sync', numori: 'End-to-end encrypted', usual: 'Readable on the server' },
    { key: 'ai', feature: 'AI training', numori: 'Never', usual: 'On by default' },
  ]"
/>

Custom cells

The #cell scoped slot renders any cell — here a badge for a status column.

Services
ServiceStatus
Syncactive
Backuppaused
<UiTable
  caption="Services"
  :columns="[
    { key: 'name', label: 'Service' },
    { key: 'status', label: 'Status' },
  ]"
  :rows="[
    { key: 'sync', name: 'Sync', status: 'active' },
    { key: 'backup', name: 'Backup', status: 'paused' },
  ]"
>
  <template #cell="{ column, value }">
    <UiBadge v-if="column.key === 'status'" :color="value === 'active' ? 'green' : 'gray'">
      {{ value }}
    </UiBadge>
    <template v-else>{{ value }}</template>
  </template>
</UiTable>

Props

NameTypeDefaultDescription
columnsrequiredarrayColumn definitions, left to right, each `{ key, label?, align?, header?, highlight?, icon?, width? }`. header renders the column as row headers (`<th scope="row">`); highlight accent-tints it; icon shows a leading MDI icon before each value; align is left/center/right.
rowsrequiredarrayRow objects, each keyed by the column `key`s.
captionstring''Table caption, rendered as a real `<caption>`. Visible by default.
hideCaptionbooleanfalseKeep the caption for assistive technology but hide it visually.
rowKeystring'key'Row field used as the v-for key; falls back to the row index.

Slots

SlotDescription
captionRich caption content (overrides the caption prop).
cellCustom cell content. Scope: `{ row, column, value }`.