|
1 | 1 | # Accessibility |
2 | 2 |
|
3 | | -TableView provides first-class accessibility support through UI Automation (UIA) peers for all its interactive elements. Screen readers, keyboard-only users, and accessibility testing tools can all navigate and interact with the control. |
| 3 | +`TableView` exposes a complete UI Automation (UIA) tree so that screen readers, keyboard-only users, and accessibility testing tools can navigate and interact with the control. Custom `AutomationPeer` classes are registered for every interactive element: the table itself, rows, cells, column headers, and row headers. |
4 | 4 |
|
5 | | -## Supported UI Automation Patterns |
| 5 | +## When to use it |
6 | 6 |
|
7 | | -| Element | UIA Patterns | |
8 | | -|---------|-------------| |
9 | | -| **TableView** | `GridPattern`, `TablePattern`, `SelectionPattern` (inherited) | |
10 | | -| **TableViewRow** | `SelectionItemPattern` (inherited), `ExpandCollapsePattern` (when row details are available and `RowDetailsVisibilityMode` is `VisibleWhenExpanded`) | |
11 | | -| **TableViewCell** | `GridItemPattern`, `TableItemPattern`, `SelectionItemPattern` | |
12 | | -| **TableViewColumnHeader** | `InvokePattern` (when `CanSort` is `true`) | |
13 | | -| **TableViewRowHeader** | _(structural header)_ | |
| 7 | +You do not need to opt in. Accessibility support is always active. This page explains what is exposed, how to improve automation names for custom content, and what limitations apply. |
| 8 | + |
| 9 | +## Supported UIA patterns |
| 10 | + |
| 11 | +| Element | UIA patterns | |
| 12 | +|---|---| |
| 13 | +| [`TableView`](xref:WinUI.TableView.TableView) | `GridPattern`, `TablePattern`, `SelectionPattern` (inherited from `ListView`) | |
| 14 | +| [`TableViewRow`](xref:WinUI.TableView.TableViewRow) | `SelectionItemPattern` (inherited), `ExpandCollapsePattern` when `RowDetailsVisibilityMode` is `VisibleWhenExpanded` | |
| 15 | +| [`TableViewCell`](xref:WinUI.TableView.TableViewCell) | `GridItemPattern`, `TableItemPattern`, `SelectionItemPattern` | |
| 16 | +| [`TableViewColumnHeader`](xref:WinUI.TableView.TableViewColumnHeader) | `InvokePattern` when [`CanSort`](xref:WinUI.TableView.TableViewColumnHeader.CanSort) is `true` | |
| 17 | +| `TableViewRowHeader` | Structural header element | |
14 | 18 |
|
15 | 19 | ### GridPattern / TablePattern (TableView) |
16 | 20 |
|
17 | | -`TableView` exposes `IGridProvider` and `ITableProvider`: |
| 21 | +`TableView` implements `IGridProvider` and `ITableProvider`: |
18 | 22 |
|
19 | | -- **`RowCount`** — number of data rows (items) |
| 23 | +- **`RowCount`** — number of data rows currently loaded |
20 | 24 | - **`ColumnCount`** — number of visible columns |
21 | | -- **`GetItem(row, column)`** — returns the automation element for the specified cell (only for realized/visible cells) |
| 25 | +- **`GetItem(row, column)`** — returns the automation element for the specified cell (only for realized, on-screen cells) |
22 | 26 | - **`GetColumnHeaders()`** — returns automation elements for all visible column headers |
23 | | -- **`RowOrColumnMajor`** — `RowMajor` |
| 27 | +- **`RowOrColumnMajor`** — always `RowMajor` |
24 | 28 |
|
25 | | -### GridItemPattern / TableItemPattern (Cells) |
| 29 | +### GridItemPattern / TableItemPattern (cells) |
26 | 30 |
|
27 | | -Each `TableViewCell` exposes: |
| 31 | +Each `TableViewCell` exposes `IGridItemProvider` and `ITableItemProvider`: |
28 | 32 |
|
29 | 33 | - **`Row`** — zero-based row index |
30 | 34 | - **`Column`** — zero-based column index |
31 | 35 | - **`RowSpan` / `ColumnSpan`** — always 1 |
32 | 36 | - **`ContainingGrid`** — the owning `TableView` |
33 | 37 | - **`GetColumnHeaderItems()`** — the column header for this cell |
34 | 38 |
|
35 | | -### SelectionItemPattern (Cells and Rows) |
| 39 | +### SelectionItemPattern (cells and rows) |
36 | 40 |
|
37 | 41 | - `IsSelected` reflects the current selection state |
38 | | -- `Select()`, `AddToSelection()`, `RemoveFromSelection()` manipulate selection |
| 42 | +- `Select()`, `AddToSelection()`, and `RemoveFromSelection()` manipulate the selection programmatically |
39 | 43 | - `SelectionContainer` returns the owning `TableView` |
40 | | -- Row selection through `ListViewItemAutomationPeer` is provided automatically by the base `ListView` infrastructure |
| 44 | +- Row `SelectionItemPattern` is provided automatically by the base `ListView` infrastructure |
41 | 45 |
|
42 | | -### InvokePattern (Column Headers) |
| 46 | +### InvokePattern (column headers) |
43 | 47 |
|
44 | | -When a column is sortable (`CanSort = true`), its header exposes `IInvokeProvider`. Invoking the header cycles sort direction: ascending → descending → unsorted. |
| 48 | +When a column is sortable ([`CanSort`](xref:WinUI.TableView.TableViewColumnHeader.CanSort) is `true`), its header exposes `IInvokeProvider`. Invoking the header cycles the sort direction: ascending → descending → unsorted. |
45 | 49 |
|
46 | | -### ExpandCollapsePattern (Row Details) |
| 50 | +### ExpandCollapsePattern (row details) |
47 | 51 |
|
48 | | -When `RowDetailsVisibilityMode` is `VisibleWhenExpanded`, each row exposes `IExpandCollapseProvider` allowing programmatic expand/collapse of its details pane. |
| 52 | +When [`RowDetailsVisibilityMode`](xref:WinUI.TableView.TableView.RowDetailsVisibilityMode) is `VisibleWhenExpanded`, each row exposes `IExpandCollapseProvider` so automation clients can expand or collapse the details pane programmatically. |
49 | 53 |
|
50 | | -## Automation Names |
| 54 | +## Automation names |
51 | 55 |
|
52 | 56 | ### TableView |
53 | | -Uses `AutomationProperties.Name` if set; otherwise the name is inherited from the base `ListView` peer. |
54 | 57 |
|
55 | | -### Column Headers |
56 | | -Format: `"{headerText}, {sortState}, {filterState}"` where sort and filter suffixes are omitted when not applicable. |
| 58 | +Uses [`AutomationProperties.Name`](https://learn.microsoft.com/en-us/windows/windows-app-sdk/api/winrt/microsoft.ui.xaml.automation.automationproperties.name) if set; otherwise inherits from the base `ListView` peer. |
57 | 59 |
|
58 | | -Examples: |
59 | | -- `"Name"` — unsorted, unfiltered |
60 | | -- `"Name, Sort Ascending"` — sorted ascending |
61 | | -- `"Name, Sort Descending, Filtered"` — sorted descending and filtered |
| 60 | +```xml |
| 61 | +<tv:TableView AutomationProperties.Name="Products table" /> |
| 62 | +``` |
| 63 | + |
| 64 | +### Column headers |
| 65 | + |
| 66 | +Format: `"{headerText}"`, with an optional sort-state suffix and filter suffix when applicable. |
| 67 | + |
| 68 | +| State | Automation name example | |
| 69 | +|---|---| |
| 70 | +| Unsorted, unfiltered | `"Name"` | |
| 71 | +| Sorted ascending | `"Name, Sort Ascending"` | |
| 72 | +| Sorted descending | `"Name, Sort Descending"` | |
| 73 | +| Sorted and filtered | `"Name, Sort Descending, Filtered"` | |
62 | 74 |
|
63 | 75 | ### Rows |
64 | | -Format: `"Row {N}"` (1-based), or the value of `AutomationProperties.Name` if set. |
65 | 76 |
|
66 | | -The help text contains a summary of all cells: `"Name: Waheed Ahmad, Age: 30, City: London"`. |
| 77 | +Format: `"Row {N}"` (1-based index). The help text contains a summary of all cells in the row, for example `"Name: Waheed Ahmad, Age: 30, City: London"`. |
67 | 78 |
|
68 | 79 | ### Cells |
| 80 | + |
69 | 81 | Format: `"{columnHeader}, Row {N}, {cellValue}"`. |
70 | 82 |
|
71 | 83 | Examples: |
| 84 | + |
72 | 85 | - `"Name, Row 3, Waheed Ahmad"` |
73 | 86 | - `"Salary, Row 7, 95000"` |
74 | 87 |
|
75 | | -Override by setting `AutomationProperties.Name` on the cell's `CellStyle`: |
| 88 | +Override the name for a specific column by setting `AutomationProperties.Name` through a `CellStyle`: |
76 | 89 |
|
77 | 90 | ```xml |
78 | | -<TableView.CellStyle> |
79 | | - <Style TargetType="tvs:TableViewCell"> |
80 | | - <Setter Property="AutomationProperties.Name" Value="Custom Cell Name" /> |
81 | | - </Style> |
82 | | -</TableView.CellStyle> |
| 91 | +<tv:TableViewTextColumn Header="Status"> |
| 92 | + <tv:TableViewTextColumn.CellStyle> |
| 93 | + <Style TargetType="tv:TableViewCell"> |
| 94 | + <Setter Property="AutomationProperties.Name" |
| 95 | + Value="{Binding StatusDescription}" /> |
| 96 | + </Style> |
| 97 | + </tv:TableViewTextColumn.CellStyle> |
| 98 | +</tv:TableViewTextColumn> |
83 | 99 | ``` |
84 | 100 |
|
85 | | -### Row Headers |
86 | | -Uses `AutomationProperties.Name` if set, otherwise the content of the row header as a string, or falls back to `"Row {N}"`. |
| 101 | +### Row headers |
87 | 102 |
|
88 | | -## Keyboard Navigation |
| 103 | +Uses `AutomationProperties.Name` if set on the `TableViewRowHeader`, otherwise derives the name from the header's content, or falls back to `"Row {N}"`. |
89 | 104 |
|
90 | | -TableView supports full keyboard navigation without breaking any existing behavior: |
| 105 | +## Keyboard navigation |
91 | 106 |
|
92 | 107 | | Key | Action | |
93 | | -|-----|--------| |
94 | | -| **Arrow Keys** | Move current cell / row | |
95 | | -| **Tab / Shift+Tab** | Move to next/previous cell | |
96 | | -| **Enter** | Move to next row cell (or commit edit) | |
97 | | -| **Space** | Select/deselect current cell or row | |
| 108 | +|---|---| |
| 109 | +| Arrow keys | Move the current cell or row | |
| 110 | +| **Tab** / **Shift+Tab** | Move to the next / previous cell | |
| 111 | +| **Enter** | Move to the next row cell, or commit an edit | |
| 112 | +| **Space** | Select or deselect the current cell or row | |
98 | 113 | | **F2** | Begin editing the current cell | |
99 | | -| **Escape** | Cancel editing | |
100 | | -| **Home / End** | Move to first/last column in row | |
101 | | -| **Ctrl+Home / Ctrl+End** | Move to first/last row | |
102 | | -| **Page Up / Page Down** | Move by one page | |
| 114 | +| **Escape** | Cancel editing and return focus to the current cell | |
| 115 | +| **Home** / **End** | Move to the first / last column in the row | |
| 116 | +| **Ctrl+Home** / **Ctrl+End** | Move to the first / last row | |
| 117 | +| **Page Up** / **Page Down** | Move by one page | |
103 | 118 | | **Ctrl+A** | Select all | |
104 | 119 | | **Ctrl+Shift+A** | Deselect all | |
105 | 120 | | **Ctrl+C** | Copy to clipboard | |
106 | 121 |
|
107 | | -## Screen Reader Behavior |
| 122 | +## Screen reader behavior |
108 | 123 |
|
109 | | -When navigating with a screen reader (e.g. Narrator on Windows): |
| 124 | +When navigating with a screen reader such as Narrator: |
110 | 125 |
|
111 | | -1. **TableView** announces itself as a "table view" with row and column counts. |
| 126 | +1. Moving to the **TableView** announces it as a table with its row and column count. |
112 | 127 | 2. Moving between **rows** announces the row number and a summary of its content. |
113 | | -3. Moving between **cells** announces the column header, row number, and current cell value. |
114 | | -4. **Column headers** announce their header text along with the current sort state and filter state. |
115 | | -5. **Editing**: When a cell enters edit mode, focus moves to the editing control (e.g. a `TextBox`), which announces itself to the screen reader independently with its own `IValueProvider`. |
| 128 | +3. Moving between **cells** announces the column header, row number, and current value. |
| 129 | +4. **Column headers** announce their header text, current sort state, and filter state. |
| 130 | +5. **Editing**: pressing **F2** (or double-tapping) enters edit mode. Focus moves to the editing control (for example, a `TextBox`), which announces itself independently with its own value. Pressing **Escape** returns focus to the cell, keeping Narrator on the correct cell. |
116 | 131 | 6. **Selection changes** are announced through `SelectionItemPattern.IsSelected`. |
117 | 132 |
|
118 | | -## How Developers Can Improve Automation Names |
| 133 | +## Custom automation names for template columns |
119 | 134 |
|
120 | | -### Custom Cell Names via Style |
| 135 | +`TableViewTemplateColumn` cells display developer-defined content. The cell automation name defaults to `"{columnHeader}, Row {N}"` unless overridden. Set `AutomationProperties.Name` directly on the root element of the template: |
121 | 136 |
|
122 | 137 | ```xml |
123 | | -<tvs:TableViewTextColumn Header="Status"> |
124 | | - <tvs:TableViewTextColumn.CellStyle> |
125 | | - <Style TargetType="tvs:TableViewCell"> |
126 | | - <Setter Property="AutomationProperties.Name" |
127 | | - Value="{Binding StatusDescription}" /> |
128 | | - </Style> |
129 | | - </tvs:TableViewTextColumn.CellStyle> |
130 | | -</tvs:TableViewTextColumn> |
| 138 | +<tv:TableViewTemplateColumn Header="Actions"> |
| 139 | + <tv:TableViewTemplateColumn.CellTemplate> |
| 140 | + <DataTemplate> |
| 141 | + <Button Content="Edit" |
| 142 | + AutomationProperties.Name="Edit row" /> |
| 143 | + </DataTemplate> |
| 144 | + </tv:TableViewTemplateColumn.CellTemplate> |
| 145 | +</tv:TableViewTemplateColumn> |
131 | 146 | ``` |
132 | 147 |
|
133 | | -### Custom Column Header Names |
| 148 | +## Custom column header names |
| 149 | + |
| 150 | +To override the automation name of a column header (for example, to provide a longer description for an abbreviated header): |
134 | 151 |
|
135 | 152 | ```xml |
136 | | -<tvs:TableViewTextColumn Header="DOB"> |
137 | | - <tvs:TableViewTextColumn.HeaderStyle> |
138 | | - <Style TargetType="tvs:TableViewColumnHeader"> |
| 153 | +<tv:TableViewTextColumn Header="DOB"> |
| 154 | + <tv:TableViewTextColumn.HeaderStyle> |
| 155 | + <Style TargetType="tv:TableViewColumnHeader"> |
139 | 156 | <Setter Property="AutomationProperties.Name" |
140 | 157 | Value="Date of Birth" /> |
141 | 158 | </Style> |
142 | | - </tvs:TableViewTextColumn.HeaderStyle> |
143 | | -</tvs:TableViewTextColumn> |
144 | | -``` |
145 | | - |
146 | | -### Custom Row Header Names |
147 | | - |
148 | | -```xml |
149 | | -<tvs:TableView.RowHeaderTemplate> |
150 | | - <DataTemplate> |
151 | | - <!-- The TableViewRowHeader automation name derives from its content --> |
152 | | - <TextBlock Text="{Binding EmployeeId}" /> |
153 | | - </DataTemplate> |
154 | | -</tvs:TableView.RowHeaderTemplate> |
155 | | -``` |
156 | | - |
157 | | -### Template Columns |
158 | | - |
159 | | -For `TableViewTemplateColumn`, set `AutomationProperties.Name` directly on the template root element: |
160 | | - |
161 | | -```xml |
162 | | -<tvs:TableViewTemplateColumn Header="Actions"> |
163 | | - <tvs:TableViewTemplateColumn.CellTemplate> |
164 | | - <DataTemplate> |
165 | | - <Button Content="Edit" |
166 | | - AutomationProperties.Name="Edit row" /> |
167 | | - </DataTemplate> |
168 | | - </tvs:TableViewTemplateColumn.CellTemplate> |
169 | | -</tvs:TableViewTemplateColumn> |
| 159 | + </tv:TableViewTextColumn.HeaderStyle> |
| 160 | +</tv:TableViewTextColumn> |
170 | 161 | ``` |
171 | 162 |
|
172 | | -## Limitations |
| 163 | +## Notes and limitations |
173 | 164 |
|
174 | | -| Limitation | Notes | |
175 | | -|------------|-------| |
176 | | -| Virtualized cells | `IGridProvider.GetItem(row, column)` returns `null` for rows that are not currently realized in the visual tree. Scroll the target row into view first if needed. | |
177 | | -| Cell value via IValueProvider | `IValueProvider` is not implemented on `TableViewCellAutomationPeer`. Instead, the editing element (e.g. `TextBox`) exposes `IValueProvider` when the cell is in edit mode. | |
178 | | -| Non-Windows platforms | Automation peers are present on all platforms (WinUI 3 and Uno Platform). However, some automation clients and assistive technologies only run on Windows. | |
179 | | -| Custom column types | `TableViewTemplateColumn` cells display developer-defined content; accessible names for those cells default to the column header + row index unless overridden by the template content. | |
| 165 | +- **Virtualized cells**: `IGridProvider.GetItem(row, column)` returns `null` for rows that are not currently in the visual tree. Scroll the target row into view before calling `GetItem`. |
| 166 | +- **IValueProvider on cells**: `IValueProvider` is not implemented on the cell peer. Instead, the editing element (for example, a `TextBox`) exposes `IValueProvider` while the cell is in edit mode. |
| 167 | +- **Custom column types**: cells in `TableViewTemplateColumn` show developer-defined content. Accessible names for those cells default to the column header and row index unless the template explicitly sets `AutomationProperties.Name`. |
| 168 | +- **Non-Windows platforms**: automation peers are compiled and run on all platforms (WinUI 3 and Uno Platform). However, not all Uno Platform targets expose a full UIA tree to assistive technologies. On WebAssembly (WASM), the platform relies on ARIA attributes managed by Uno. On Desktop Skia targets, accessibility support depends on the native platform's accessibility APIs. |
180 | 169 |
|
181 | | -## Uno Platform Notes |
| 170 | +## Related articles |
182 | 171 |
|
183 | | -Automation peers compile and run on all Uno Platform targets. However, not all Uno Platform targets expose a full UIA tree to assistive technologies. On WebAssembly (WASM), the platform relies on ARIA attributes which Uno manages separately. On Desktop Skia targets, accessibility support depends on the platform's native accessibility APIs. |
| 172 | +- [Selection](selection.md) |
| 173 | +- [Editing](editing.md) |
| 174 | +- [Sorting](sorting.md) |
| 175 | +- [Filtering](filtering.md) |
| 176 | +- [Row details](row-details.md) |
| 177 | +- [Row headers](row-headers.md) |
| 178 | +- [Styling rows, cells, and headers](styling.md) |
184 | 179 |
|
185 | | -If a particular automation pattern is not needed for non-Windows targets, guard it with `#if WINDOWS` as shown in the rest of the codebase. |
0 commit comments