Repository navigation
table: Expose DataTable's structure and cells to assistive technology - #3667
Merged
Merged
Conversation
DataTable only gave each row `Role::Row`, so a screen reader found a flat list of unnamed rows: no table, no column headers, and no cell content, because GPUI exposes no plain text to the accessibility tree. - The table is a `Grid` (a `Table` when nothing is selectable), with row and column counts covering every row, not just the rendered ones. - The header is a row of `ColumnHeader`s named after their columns. - Body cells are `Cell`s, or `GridCell`s that report their selection in cell selection mode, with their column index. Rows carry their row index; the header row is row 0. - `TableDelegate::cell_label` lets a delegate name its cells. It defaults to `None` and is only called while assistive technology is active. The DataTable story names its cells with the text it already draws. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #3647 (items 1–3: container, header cells, body cells).
Description
DataTableonly gave each rowRole::Row. A screen reader found a flat list of unnamed rows: no table, no column headers, and no cell content, because GPUI only exposes text that is aTextwith an id. This PR exposes the table's structure.table-inneris aGrid, or aTablewhen neither rows nor cells are selectable. It setsaria_row_count(rows_count + 1)andaria_column_count(columns_count). The table is virtualized, so the counts cover every row, not just the rendered ones.Rowataria_row_index(0). Each leaf header is aColumnHeadernamed after its column (aria_label(column.name)), with itsaria_column_index. The "Sort by …" button stays inside it.aria_row_index(row_ix + 1). Each cell is aCellwith itsaria_column_index. In cell selection mode it is aGridCellwitharia_selected, which AccessKit's Windows adapter reports throughSelectionItemPattern.TableDelegate::cell_labellets a delegate name its cells. It defaults toNone, so existing delegates are unaffected. It is only called whilewindow.is_a11y_active()(or undertest-support), the same gateInputStateuses for its value. That way a delegate's formatting costs nothing when no assistive technology is connected.cell_labelwith the text it already draws (format_cell).Public API
gpui-component
TableDelegate::cell_label(&self, row_ix: usize, col_ix: usize, cx: &App) -> Option<SharedString>: the text a screen reader reads for a cell. Defaults toNone.Screenshot
UI Automation tree of
cargo run -p gpui-component-story -- datatable(Windows 11, read with UIA's control view):DataItem ""plus 4 "Sort by" buttons.How to Test
cargo test -p gpui-kit --features test-support,component --test integration: 419 passed. Two tests are new:table_exposes_its_header_and_cells_to_assistive_technology: aGridcontainer,ColumnHeaders named "Name"/"Status", and a cell with the delegate's label.selectable_cells_report_their_selection:GridCells reportselected.state.rschange.cargo run -p gpui-component-story -- datatablewith Accessibility Insights for Windows or Narrator: the tree above.cargo clippy -p gpui-component -p gpui-component-story --all-targets -- -D warningsandcargo fmt --checkare clean.Not in this PR
accesskit_windows(0.34 and 0.35) only exposesSelectionItemPatternfor list, tree and tab items and forGridCell, with a// TODO: tables (#29)for rows. Cell selection works throughGridCell.render_group_th) and the row header column (cell_selectable+row_header) get no role yet.Open questions
GridvsTable: I made the container aGridwhenever rows or cells are selectable (the default), and aTableotherwise. Happy to use one role for both.cell_labelnaming: fine as is, or would you prefer another name (e.g.accessible_cell_text)?I've only tested on Windows (UI Automation); I haven't tried VoiceOver on macOS.
Checklist
cargo runfor story tests related to the changes.🤖 Generated with Claude Code