From 096e3ee409dce11affde4de4eea3f80c1f3ee773 Mon Sep 17 00:00:00 2001
From: seonghobae <8172694+seonghobae@users.noreply.github.com>
Date: Tue, 28 Jul 2026 02:50:51 +0000
Subject: [PATCH] UX: Improve HTML report table accessibility with row headers
Updates the standalone HTML report generator to use `
`
for the first column in data tables instead of standard ` | ` cells.
This improves screen reader accessibility by creating a clear semantic
relationship between the identifying row header and its corresponding
data cells.
Also updates base CSS selectors (`thead th, tbody th, td`) to ensure
visual parity is maintained and adds `font-variant-numeric: tabular-nums`
so that numbers perfectly align vertically across rows.
---
.jules/palette.md | 4 ++++
python/fast_mlsirm/report.py | 26 ++++++++++++++++++--------
2 files changed, 22 insertions(+), 8 deletions(-)
diff --git a/.jules/palette.md b/.jules/palette.md
index 74cddb7ad..7a115b91b 100644
--- a/.jules/palette.md
+++ b/.jules/palette.md
@@ -19,3 +19,7 @@
## 2024-07-13 - CLI Debugging Stack Traces
**Learning:** Adding a `FAST_MLSIRM_DEBUG` bypass to user-friendly `try/except` blocks is crucial for DX. Otherwise, unexpected runtime errors during development will be swallowed into generic stderr messages, hiding the stack trace needed to actually fix the bug.
**Action:** When adding `try-except` blocks to Python CLI subcommands to improve Developer Experience (DX) by preventing raw tracebacks for users, include a debug bypass (e.g., `if os.environ.get("FAST_MLSIRM_DEBUG"): raise`) in *all* catch blocks (including `RuntimeError` and `Exception`) to ensure tracebacks aren't swallowed during local development and debugging.
+
+## 2026-07-28 - Table Row Header Accessibility
+**Learning:** When generating HTML data tables for reports, using ` | ` for the first identifying column improves screen reader accessibility by clearly associating the row header with its corresponding data cells. Additionally, applying `font-variant-numeric: tabular-nums;` ensures numbers align properly in columns for better visual tracking.
+**Action:** Always use ` | ` for the primary identifying cell in a table row, update base CSS selectors (like `thead th, tbody th, td`) to include the new tags to prevent visual regressions, and apply tabular-nums for numeric alignment in data-heavy tables.
diff --git a/python/fast_mlsirm/report.py b/python/fast_mlsirm/report.py
index 30ee4276b..c92abf6ad 100644
--- a/python/fast_mlsirm/report.py
+++ b/python/fast_mlsirm/report.py
@@ -317,11 +317,14 @@ def _table(rows: list[dict[str, Any]], *, label: str, limit: int = 12) -> str:
columns = _columns(rows)
body_rows = []
for row in rows[:limit]:
- cells = "".join(
- f" | {escape(_format_value(row.get(column, '')))} | "
- for column in columns
- )
- body_rows.append(f"{cells}
")
+ cells = []
+ for index, column in enumerate(columns):
+ val = escape(_format_value(row.get(column, "")))
+ if index == 0:
+ cells.append(f'{val} | ')
+ else:
+ cells.append(f"{val} | ")
+ body_rows.append(f"{''.join(cells)}
")
note = ""
described_by = ""
@@ -679,21 +682,28 @@ def _css() -> str:
border: 0;
}
-th,
+thead th,
+tbody th,
td {
padding: 10px 12px;
text-align: left;
border-bottom: 1px solid var(--line);
white-space: nowrap;
+ font-variant-numeric: tabular-nums;
}
-th {
+thead th {
background: #f1f4ef;
color: #2f3437;
font-size: 0.8rem;
}
-tr:last-child td {
+tbody th {
+ font-weight: normal;
+}
+
+tr:last-child td,
+tr:last-child th {
border-bottom: 0;
}