Sorting

Order the rows by a column, and by further columns where the first ties. Reach for a sort order of your own where the value is an object.

import { useTable } from "@umriss-ui/table";

Examples

Sort by several columns

A click on a header sorts, Shift and click adds a level; defaultSort takes the levels the table starts with.

import { useTable } from "@umriss-ui/table";

interface Incident {
  id: string;
  title: string;
  severity: "SEV1" | "SEV2" | "SEV3";
  opened: Date;
  assignee: string;
}

const at = (day: number, hours: number, minutes: number) => new Date(2026, 2, day, hours, minutes);

const INCIDENTS: Incident[] = [
  { id: "INC-1048", title: "Checkout slow, card payments time out", severity: "SEV1", opened: at(17, 9, 42), assignee: "Jonas Keller" },
  { id: "INC-1047", title: "Webhook deliveries delayed", severity: "SEV3", opened: at(17, 7, 15), assignee: "Ines Duarte" },
  { id: "INC-1046", title: "Thumbnails missing for new uploads", severity: "SEV2", opened: at(16, 22, 5), assignee: "Tomasz Nowak" },
  { id: "INC-1045", title: "Sign-in codes arrive late", severity: "SEV2", opened: at(16, 14, 20), assignee: "Ada Mwangi" },
  { id: "INC-1043", title: "Search returns no results for some regions", severity: "SEV1", opened: at(14, 18, 30), assignee: "Leila Haddad" },
  { id: "INC-1042", title: "Duplicate reminder e-mails", severity: "SEV3", opened: at(13, 8, 45), assignee: "Sam Okafor" },
];

export default function SortBySeveralColumns() {
  const { Table, Column } = useTable(INCIDENTS, {
    rowKey: (i) => i.id,
    defaultSort: [
      { column: "severity", direction: "asc" },
      { column: "opened", direction: "desc" },
    ],
  });

  return (
    <Table ariaLabel="Incidents, most severe and newest first">
      <Column value="id" label="Incident" rowHeader />
      <Column value="title" label="Title" />
      <Column value="severity" label="Severity" />
      <Column value="opened" label="Opened" format="dateTime" />
      <Column value="assignee" label="Assignee" />
    </Table>
  );
}

Sort and export a value that is an object

A value without an order or a text form needs children; sortValue gives what to sort by, exportValue the text for the file.

import { useState } from "react";
import { Stack, Text } from "@umriss-ui/core";
import { Export, Toolbar, useTable } from "@umriss-ui/table";

interface Parcel {
  id: string;
  size: { length: number; width: number; height: number };
}

const PARCELS: Parcel[] = [
  { id: "FP-1004210", size: { length: 60, width: 40, height: 40 } },
  { id: "FP-1004223", size: { length: 30, width: 20, height: 10 } },
  { id: "FP-1004236", size: { length: 120, width: 60, height: 20 } },
];

export default function OwnOrdering() {
  const [csv, setCsv] = useState("Not exported yet.");
  const { Table, Column } = useTable(PARCELS, { rowKey: (p) => p.id });

  return (
    <Stack gap={3}>
      <Table ariaLabel="Parcels">
        <Toolbar>
          <Export onExport={setCsv} />
        </Toolbar>
        <Column value="id" label="Parcel" rowHeader />
        <Column
          value="size"
          label="Size (cm)"
          sortValue={(s) => s.length * s.width * s.height}
          exportValue={(s) => `${s.length} x ${s.width} x ${s.height}`}
        >
          {(s) => `${s.length} × ${s.width} × ${s.height}`}
        </Column>
      </Table>
      <Text as="pre" size="xs" mono>
        {csv}
      </Text>
    </Stack>
  );
}

Keyboard

Key Action
Shift + click On a header: adds the column as a further sort level.

Props on this page

From TableProps — the full table stands on First table.

NameTypeDefaultDescription
childrenReactNode—Columns, RowDetail, RowActions and the unbound parts.

Accessibility

NameTypeDefaultDescription
ariaLabelstring—Accessible name of the table (not of the outer frame).

From TableOptions — the full table stands on First table.

NameTypeDefaultDescription
rowKeyrequired(row: Z) => string—A stable key per row – the basis of selection and expansion.
defaultSort| SortLevel
| readonly SortLevel[]
| null
nullThe application's sort; it is the default that view leaves out.

From FieldColumn — the full table stands on Column.

NameTypeDefaultDescription
valuerequiredK—A field of the row. Supplies the column's id at the same time.
formatFormatFor<Z[K]>—A standard presentation by name: "percent", "count" or { decimals } for numbers, "date", "time" or "dateTime" for points in time. Alignment, sorting, export and footer stay with the value.
childrenPresentation<Z[K], Z>—How the value appears: (value, row). Never called for an absent value. Required where the value has no text form.

From ColumnBase — the full table stands on Column.

NameTypeDefaultDescription
labelrequiredstring—Names the column in its header, in the column menu and in the header row of the export.
rowHeaderboolean—This column names the row: row header cells, never hideable, the column stickyRowHeader pins, and the name by which the row's selection, expander and actions are read out. At most one per table.

From ValuePaths — the full table stands on Column.

NameTypeDefaultDescription
sortValue(value: Present<W>) => string | number | Absent—What is sorted by, when not by the value itself.
exportValue(value: Present<W>) => string | number | Absent—What stands in the export, when not the value itself.

From ToolbarProps — the full table stands on Toolbar.

NameTypeDefaultDescription
childrenReactNode—Search, column menu, export – on the left in the table toolbar, before the conditions.

From ExportProps — the full table stands on Export.

Events

NameTypeDefaultDescription
onExport(text: string) => void—Gets the text instead of triggering a file.

Known limits

What umriss deliberately does not build, and why: ADR-0032.

Every page of @umriss-ui/table

Getting started

Columns

Finding rows

Grouping

Rows

Around the table

Many rows

Editing

Limits and alarms

API index