# Table `defaultSortDirection` — draft reference

Not yet published. Extracted from the xmlui docs source for early testing.

Pairs with standalone build sha256
cf1e8ca4a9f1df559b3dd5cecb1f6d3486bb5645736c0bfb9e081d0b4072c5b2
(built 2026-08-26T20:25:06Z), which is the first build containing this property.

Two behaviours most likely to read as bugs, both documented below:

- `defaultSortDirection` sorts nothing on load. It only sets which way clicking
  starts. To open already sorted you also need `sortBy`.
- A seeded table's first click *advances* the cycle rather than confirming it,
  so on a seeded column the first click looks like it reverses the sort.

---

### `defaultSortDirection` [#defaultsortdirection]

> [!DEF]  default: **"ascending"**

Sets which direction the *first* click on a column header sorts. Use `descending` for tables whose interesting rows are the largest ones (counts, totals, percentages), so one click gives the useful order instead of two. The click cycle keeps three states and only its starting point moves: with `descending` it runs descending, ascending, unsorted. Individual `Column` components override this with their own `defaultSortDirection`. It also supplies the initial direction when [`sortBy`](#sortby) is set without an explicit [`sortDirection`](#sortdirection), so a table declared biggest-first opens that way rather than needing a click.

Available values: `ascending` **(default)**, `descending`

Some columns are only interesting from the top: vote counts, totals, percentages.
A header click sorts ascending first, so those columns cost an extra click before
they show anything useful. `defaultSortDirection` moves where the click cycle
starts.

### The problem [#the-problem]

No configuration here. Click **Votes** once and you get the *smallest* count
first; click again for the largest.

```xmlui copy
<Table data='{[...]}'>
  <Column bindTo="candidate"/>
  <Column bindTo="votes" canSort="true"/>
</Table>
```

```xmlui-pg name="Example: two clicks to see the winner"
<App>
  <Table data='{[
      { id: 1, candidate: "Ada", votes: 4820 },
      { id: 2, candidate: "Grace", votes: 9137 },
      { id: 3, candidate: "Alan", votes: 2044 },
      { id: 4, candidate: "Edsger", votes: 6610 }
    ]}'>
    <Column bindTo="candidate"/>
    <Column bindTo="votes" canSort="true"/>
  </Table>
</App>
```

Two clicks to answer "who won". On one table that is a shrug; across a screenful
of count columns it is the difference between a table you read and a table you
operate.

### One line fixes the click count [#one-line-fixes-the-click-count]

```xmlui copy /defaultSortDirection="descending"/
<Table data='{[...]}' defaultSortDirection="descending">
  <Column bindTo="candidate"/>
  <Column bindTo="votes" canSort="true"/>
</Table>
```

```xmlui-pg name="Example: defaultSortDirection on the table" /defaultSortDirection="descending"/
<App>
  <Table
    data='{[
      { id: 1, candidate: "Ada", votes: 4820 },
      { id: 2, candidate: "Grace", votes: 9137 },
      { id: 3, candidate: "Alan", votes: 2044 },
      { id: 4, candidate: "Edsger", votes: 6610 }
    ]}'
    defaultSortDirection="descending">
    <Column bindTo="candidate"/>
    <Column bindTo="votes" canSort="true"/>
  </Table>
</App>
```

Click **Votes** once: biggest first. The cycle still has three states and still
ends unsorted — descending, ascending, unsorted. Only its starting point moved.

### Opening already sorted [#opening-already-sorted]

The property above says *which direction*. It never says *which column*, so the
table still opens unsorted until you click. To arrive sorted, name the column
with [`sortBy`](#sortby):

```xmlui copy /sortBy="votes"/
<Table data='{[...]}' sortBy="votes" defaultSortDirection="descending">
  <Column bindTo="candidate"/>
  <Column bindTo="votes" canSort="true"/>
</Table>
```

```xmlui-pg name="Example: sortBy with defaultSortDirection" /sortBy="votes"/
<App>
  <Table
    data='{[
      { id: 1, candidate: "Ada", votes: 4820 },
      { id: 2, candidate: "Grace", votes: 9137 },
      { id: 3, candidate: "Alan", votes: 2044 },
      { id: 4, candidate: "Edsger", votes: 6610 }
    ]}'
    sortBy="votes"
    defaultSortDirection="descending">
    <Column bindTo="candidate"/>
    <Column bindTo="votes" canSort="true"/>
  </Table>
</App>
```

Zero clicks: biggest first on load. `defaultSortDirection` supplies the opening
direction because no explicit [`sortDirection`](#sortdirection) was given — set
that instead when the opening order should differ from what clicking produces.

A seeded table is already **at the first stage of the cycle**, so the first click
advances to the second stage rather than confirming the first. Clicking **Votes**
here goes to ascending, then to unsorted. That is worth knowing before it
surprises you: on a seeded column, the first click looks like it reverses the
sort.

### One column that reads the other way [#one-column-that-reads-the-other-way]

Names are the case where alphabetical is the natural first read, even in a table
of counts. A `Column` overrides its table:

```xmlui copy /defaultSortDirection="ascending"/
<Table data='{[...]}' defaultSortDirection="descending">
  <Column bindTo="candidate" canSort="true" defaultSortDirection="ascending"/>
  <Column bindTo="votes" canSort="true"/>
</Table>
```

```xmlui-pg name="Example: per-column override" /defaultSortDirection="ascending"/
<App>
  <Table
    data='{[
      { id: 1, candidate: "Ada", votes: 4820 },
      { id: 2, candidate: "Grace", votes: 9137 },
      { id: 3, candidate: "Alan", votes: 2044 },
      { id: 4, candidate: "Edsger", votes: 6610 }
    ]}'
    defaultSortDirection="descending">
    <Column bindTo="candidate" canSort="true" defaultSortDirection="ascending"/>
    <Column bindTo="votes" canSort="true"/>
  </Table>
</App>
```

Neither column is sorted on load — there is no `sortBy` here. Click **Votes** and
it goes largest-first; click **Candidate** and it goes A–Z. Resolution is column
first, then table, then `ascending`.

Switching columns **restarts the cycle** at the new column's own first direction;
it does not carry the previous column's stage across. Clicking **Votes** then
**Candidate** gives descending then ascending, each column's own default.

