+ // role="log" + aria-live announces streaming assistant tokens, tool-call
+ // cards, and tool results to screen readers as they arrive, instead of the
+ // response being silent until the user re-navigates the list.
+
{messages.map((m) => (
))}
diff --git a/ui/src/components/common/data-table-sort-header.tsx b/ui/src/components/common/data-table-sort-header.tsx
index 5f3e7986..ace62222 100644
--- a/ui/src/components/common/data-table-sort-header.tsx
+++ b/ui/src/components/common/data-table-sort-header.tsx
@@ -79,6 +79,20 @@ function currentDir(activeSort: string | null, sortKey: string, codec?: SortCode
return defaultCurrentDir(activeSort, sortKey);
}
+/**
+ * The `aria-sort` token for a column, to be placed on its `
` /
+ * columnheader element (that's the only element where `aria-sort` is honored —
+ * not an inner span). Exported so `` can set it on ``.
+ */
+export function ariaSortForColumn(
+ activeSort: string | null,
+ sortKey: string,
+ codec?: SortCodec,
+): 'ascending' | 'descending' | 'none' {
+ const dir = currentDir(activeSort, sortKey, codec);
+ return dir === 'asc' ? 'ascending' : dir === 'desc' ? 'descending' : 'none';
+}
+
/**
* Three-state cycle, with `sortDirections` constraint.
*
@@ -132,7 +146,9 @@ export function DataTableSortHeader({
}: DataTableSortHeaderProps) {
const dir = currentDir(activeSort, sortKey, sortCodec);
const buttonId = useId();
- const ariaSort = dir === 'asc' ? 'ascending' : dir === 'desc' ? 'descending' : 'none';
+ // aria-sort now lives on the (columnheader) in , where
+ // it's actually honored; the sr-only "Sorted …" text below conveys state on
+ // focus regardless.
const Chevron = dir === 'asc' ? ChevronUp : dir === 'desc' ? ChevronDown : ChevronsUpDown;
const chevronClass = dir === null ? 'opacity-40' : '';
@@ -153,7 +169,7 @@ export function DataTableSortHeader({
};
return (
-
+