Tables

Summary

Data tables for tabular content. Two opt-in modifiers add interactivity (row hover) and column sorting. The sortable modifier reads aria-sort on each <th> and toggles the clicked column between ascending and descending (other columns lose their aria-sort).

When to use

VariantUse it for
Plain
.neura-table
Static tabular data: read-only summaries, configuration values, two-column key-value pairs.
Interactive
.neura-table-interactive
Modifier: adds row hover. Use when rows link to a detail view or are otherwise clickable.
Sortable
.neura-table-sortable
Modifier: clickable (and keyboard-operable) column headers toggle aria-sort. Pairs with .neura-table-interactive.
Unsortable column
.neura-table-column-unsortable
Per-th modifier: opts a single column out of sorting (e.g. an actions column).
Zebra
.neura-table-zebra
Modifier: tints even rows and drops the row borders in favour of the stripes. For dense listings where per-row borders get noisy.

Examples

Sortable + interactive table. Click any header cell to toggle aria-sort ascending ↔ descending, hover rows to highlight, and verify lozenge cells render with the expected status colors.

Name Email Role Status Actions
Alice alice@example.com Admin active Edit
Bob bob@example.com Editor pending Edit
Carol carol@example.com Viewer disabled Edit

HTML

Plain table: no interactivity, no sort. An optional <caption> renders as a tinted title bar above the table (caption-side: top).

<table class="neura-table">
  <thead>
    <tr><th>Name</th><th>Email</th></tr>
  </thead>
  <tbody>
    <tr><td>Alice</td><td>alice@example.com</td></tr>
    <tr><td>Bob</td><td>bob@example.com</td></tr>
  </tbody>
</table>

Interactive + sortable. Set the initial sort column via aria-sort:

<table class="neura-table neura-table-interactive neura-table-sortable">
  <thead>
    <tr>
      <th aria-sort="ascending">Name</th>
      <th>Email</th>
      <th class="neura-table-column-unsortable">Actions</th>
    </tr>
  </thead>
  <tbody>
    <!-- rows -->
  </tbody>
</table>

Lozenges in cells (see .neura-lozenge for status pills):

<td><span class="neura-lozenge neura-lozenge-success">active</span></td>
<td><span class="neura-lozenge neura-lozenge-error">disabled</span></td>

CSS classes

ClassEffect
.neura-tableBase styling: borders, padding, header weight, caption bar.
.neura-table-interactiveModifier: adds row hover background.
.neura-table-sortableModifier: clickable headers cycle aria-sort. Adds the sort caret; hovering an unsorted column previews a faint one.
.neura-table-column-unsortableOn a <th>: exempts that column from the sort handler.
.neura-table-zebraModifier: even-row striping instead of row borders (AUI: table.aui.aui-zebra).

Attributes

AttributeEffect
aria-sort="ascending"Marks the column as currently sorted ascending. Visual caret + screen-reader cue.
aria-sort="descending"Currently sorted descending.
aria-sort="none"Sortable but not currently sorted.

JavaScript

Sorting is a Neura-native component. Every table.neura-table-sortable auto-inits on DOMContentLoaded: headers become clickable and keyboard-operable (focusable, Enter/Space), rows reorder alphabetically / numerically, and aria-sort tracks the active column. No JS is needed for static markup.

API

MemberDescription
Neura.sortableTable(tableOrSelector)Get the singleton instance for a table (binds its headers on first call).
.sort(column[, direction])Sort imperatively: column is a zero-based index or a <th>; direction is 'ascending' / 'descending' (defaults to the same toggle a click performs).
.refresh()Bind headers added after init (re-rendered thead).
.on('sort', fn) / .off('sort', fn)The neura-table-sort CustomEvent (detail: { th, columnIndex, direction }), fired after each sort.
.destroy()Unbind all headers and forget the instance.

Manual setup (e.g. for a table inserted after page load):

const st = Neura.sortableTable('#report');

// Sort the second column descending without a click:
st.sort(1, 'descending');

// React to sorting:
st.on('sort', (e) => {
  console.log(e.detail.columnIndex, e.detail.direction);
});

If you need custom sort logic (e.g. dates, mixed types), do it yourself and just keep aria-sort in sync:

document.querySelector('th.date-col').addEventListener('click', (e) => {
  const th = e.currentTarget;
  const dir = th.getAttribute('aria-sort') === 'ascending' ? 'descending' : 'ascending';
  // ... sort the rows however you want ...
  th.setAttribute('aria-sort', dir);
});

AUI compatibility

table.aui, .aui-table-interactive, .aui-table-sortable, table.aui.aui-zebra, and .aui-table-column-unsortable all alias to the Neura rules. AJS.tablessortable.setup() is a compat alias over Neura.sortableTable. It normalizes the legacy aui-* marker classes and delegates, so legacy markup sorts identically and auto-inits on every page load.