Components / Data

Table

Compose responsive data tables with semantic rows, headers, and cells.

Preview

InvoiceCustomerStatusTotal
INV-1042Ana MartinsPaid€420.00
INV-1043Northstar SARLPending€860.00
INV-1044Studio FormaDraft€195.00

Use cases

Invoice list

Compare several records with aligned totals and clear column headers.

Sortable report

Display the current sort direction on the sorted header.

Usage example

Vue
<script setup lang="ts">
import { Table, TableBody, TableCell, TableHeader, TableRow } from './components'

const columns = [
  { key: 'invoice', label: 'Invoice' },
  { key: 'total', label: 'Total', align: 'end' as const },
]
</script>

<template>
  <Table aria-label="Invoices" size="sm">
    <TableHeader :columns="columns" />
    <TableBody>
      <TableRow><TableCell>INV-1042</TableCell><TableCell align="end">€420</TableCell></TableRow>
    </TableBody>
  </Table>
</template>

More examples

Invoices

Build a semantic table with a header definition and body rows.

Invoices
<script setup lang="ts">
import Table from './components/ui/table/Table.vue'
import TableBody from './components/ui/table/TableBody.vue'
import TableCell from './components/ui/table/TableCell.vue'
import TableHeader from './components/ui/table/TableHeader.vue'
import TableRow from './components/ui/table/TableRow.vue'
const columns = [{ key: 'invoice', label: 'Invoice' }, { key: 'total', label: 'Total', align: 'end' as const }]
const rows = [{ id: 'INV-1042', total: '€420' }, { id: 'INV-1043', total: '€85' }]
</script>

<template>
  <Table aria-label="Invoices"><TableHeader :columns="columns" /><TableBody>
    <TableRow v-for="row in rows" :key="row.id"><TableCell>{{ row.id }}</TableCell><TableCell align="end">{{ row.total }}</TableCell></TableRow>
  </TableBody></Table>
</template>

Sorted inventory

Expose the currently sorted column in the header.

Sorted inventory
<script setup lang="ts">
import Table from './components/ui/table/Table.vue'
import TableBody from './components/ui/table/TableBody.vue'
import TableCell from './components/ui/table/TableCell.vue'
import TableHeader from './components/ui/table/TableHeader.vue'
import TableRow from './components/ui/table/TableRow.vue'
const columns = [{ key: 'name', label: 'Name', ariaSort: 'ascending' as const }, { key: 'stock', label: 'In stock', align: 'end' as const }]
</script>

<template>
  <Table aria-label="Inventory" size="sm"><TableHeader :columns="columns" /><TableBody>
    <TableRow><TableCell>Notebook</TableCell><TableCell align="end">24</TableCell></TableRow>
  </TableBody></Table>
</template>

Key API

The most useful props, models, slots, events, and methods for this component.

Key API for Table
NameTypeDefault or requirement
Table sizesm | md | lgmd
TableHead aria-sortnone | ascending | descending | otherundefined
TableHeader columns(string | { key; label; align?; scope?; ariaSort? })[][]
TableHead / TableCell alignstart | center | endstart
defaultnative table-content slotsrequired

Use TableHeader columns for a simple header, or compose TableRow and TableHead for grouped headers. Add sorting, filtering, selection, pagination, or server data in your application.

Implementation notes

  • Keep row cell order aligned with the header order.
  • Update both sorted data and ariaSort when the user chooses a different sort column.

Accessibility and localization

  • Name a table when surrounding text does not already identify it; scope and aria-sort help readers understand columns.
Weini UIDesign system · Vue component library · Free and public