@alaarab/ogrid-mcp 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/README.md +68 -0
  2. package/bundled-docs/api/README.md +94 -0
  3. package/bundled-docs/api/column-def.mdx +379 -0
  4. package/bundled-docs/api/components-column-chooser.mdx +310 -0
  5. package/bundled-docs/api/components-column-header-filter.mdx +363 -0
  6. package/bundled-docs/api/components-datagrid-table.mdx +316 -0
  7. package/bundled-docs/api/components-pagination-controls.mdx +344 -0
  8. package/bundled-docs/api/components-sidebar.mdx +427 -0
  9. package/bundled-docs/api/components-status-bar.mdx +309 -0
  10. package/bundled-docs/api/grid-api.mdx +299 -0
  11. package/bundled-docs/api/js-api.mdx +198 -0
  12. package/bundled-docs/api/ogrid-props.mdx +244 -0
  13. package/bundled-docs/api/types.mdx +640 -0
  14. package/bundled-docs/features/cell-references.mdx +225 -0
  15. package/bundled-docs/features/column-chooser.mdx +279 -0
  16. package/bundled-docs/features/column-groups.mdx +290 -0
  17. package/bundled-docs/features/column-pinning.mdx +282 -0
  18. package/bundled-docs/features/column-reordering.mdx +359 -0
  19. package/bundled-docs/features/column-types.mdx +181 -0
  20. package/bundled-docs/features/context-menu.mdx +216 -0
  21. package/bundled-docs/features/csv-export.mdx +227 -0
  22. package/bundled-docs/features/editing.mdx +377 -0
  23. package/bundled-docs/features/filtering.mdx +330 -0
  24. package/bundled-docs/features/formulas.mdx +381 -0
  25. package/bundled-docs/features/grid-api.mdx +311 -0
  26. package/bundled-docs/features/keyboard-navigation.mdx +236 -0
  27. package/bundled-docs/features/pagination.mdx +245 -0
  28. package/bundled-docs/features/performance.mdx +433 -0
  29. package/bundled-docs/features/row-selection.mdx +256 -0
  30. package/bundled-docs/features/server-side-data.mdx +291 -0
  31. package/bundled-docs/features/sidebar.mdx +234 -0
  32. package/bundled-docs/features/sorting.mdx +241 -0
  33. package/bundled-docs/features/spreadsheet-selection.mdx +201 -0
  34. package/bundled-docs/features/status-bar.mdx +205 -0
  35. package/bundled-docs/features/toolbar.mdx +284 -0
  36. package/bundled-docs/features/virtual-scrolling.mdx +624 -0
  37. package/bundled-docs/getting-started/installation.mdx +216 -0
  38. package/bundled-docs/getting-started/overview.mdx +151 -0
  39. package/bundled-docs/getting-started/quick-start.mdx +425 -0
  40. package/bundled-docs/getting-started/vanilla-js.mdx +191 -0
  41. package/bundled-docs/guides/accessibility.mdx +550 -0
  42. package/bundled-docs/guides/controlled-vs-uncontrolled.mdx +153 -0
  43. package/bundled-docs/guides/custom-cell-editors.mdx +201 -0
  44. package/bundled-docs/guides/framework-showcase.mdx +200 -0
  45. package/bundled-docs/guides/mcp-live-testing.mdx +291 -0
  46. package/bundled-docs/guides/mcp.mdx +172 -0
  47. package/bundled-docs/guides/migration-from-ag-grid.mdx +223 -0
  48. package/bundled-docs/guides/theming.mdx +211 -0
  49. package/dist/esm/bridge-client.d.ts +87 -0
  50. package/dist/esm/bridge-client.js +162 -0
  51. package/dist/esm/index.js +1060 -0
  52. package/package.json +43 -0
@@ -0,0 +1,310 @@
1
+ ---
2
+ sidebar_position: 12
3
+ title: ColumnChooser
4
+ ---
5
+
6
+ # ColumnChooser
7
+
8
+ A dropdown component that allows users to show/hide columns in the grid. Displays a list of all columns with checkboxes, and provides "Select All" and "Clear All" actions.
9
+
10
+ ## Import
11
+
12
+
13
+ <Tabs groupId="framework">
14
+ <TabItem value="react" label="React">
15
+
16
+ ```typescript
17
+ // or
18
+ // or
19
+ ```
20
+
21
+ </TabItem>
22
+ <TabItem value="angular" label="Angular">
23
+
24
+ ```typescript
25
+ // or
26
+ // or
27
+ ```
28
+
29
+ </TabItem>
30
+ <TabItem value="vue" label="Vue">
31
+
32
+ ```typescript
33
+ // or
34
+ // or
35
+ ```
36
+
37
+ </TabItem>
38
+ <TabItem value="js" label="Vanilla JS">
39
+
40
+ ```typescript
41
+ // ColumnChooser is an internal component in vanilla JS
42
+ ```
43
+
44
+ </TabItem>
45
+ </Tabs>
46
+
47
+ ## Props (React)
48
+
49
+ | Prop | Type | Default | Description |
50
+ |------|------|---------|-------------|
51
+ | `columns` | `IColumnDefinition[]` | **Required** | Array of all columns (visible and hidden). |
52
+ | `visibleColumns` | `Set<string>` | **Required** | Set of currently visible column IDs. |
53
+ | `onVisibilityChange` | `(columnKey: string, visible: boolean) => void` | **Required** | Callback when a column's visibility is toggled. |
54
+ | `className` | `string` | `undefined` | Additional CSS class for the root element. |
55
+
56
+ ## IColumnDefinition
57
+
58
+ Minimal column info used by the column chooser:
59
+
60
+ ```typescript
61
+ interface IColumnDefinition {
62
+ columnId: string;
63
+ name: string;
64
+ required?: boolean;
65
+ }
66
+ ```
67
+
68
+ | Field | Type | Description |
69
+ |-------|------|-------------|
70
+ | `columnId` | `string` | Unique column identifier. |
71
+ | `name` | `string` | Display name shown in the dropdown. |
72
+ | `required` | `boolean` | When `true`, the checkbox is disabled (column cannot be hidden). |
73
+
74
+ ## Usage
75
+
76
+ ### Basic Example (React)
77
+
78
+ ```tsx
79
+
80
+ function MyApp() {
81
+ const columns: IColumnDefinition[] = [
82
+ { columnId: 'id', name: 'ID', required: true },
83
+ { columnId: 'name', name: 'Product Name' },
84
+ { columnId: 'price', name: 'Price' },
85
+ { columnId: 'category', name: 'Category' },
86
+ ];
87
+
88
+ const [visibleColumns, setVisibleColumns] = useState<Set<string>>(
89
+ new Set(['id', 'name', 'price'])
90
+ );
91
+
92
+ const handleVisibilityChange = (columnKey: string, visible: boolean) => {
93
+ const newSet = new Set(visibleColumns);
94
+ if (visible) {
95
+ newSet.add(columnKey);
96
+ } else {
97
+ newSet.delete(columnKey);
98
+ }
99
+ setVisibleColumns(newSet);
100
+ };
101
+
102
+ return (
103
+ <ColumnChooser
104
+ columns={columns}
105
+ visibleColumns={visibleColumns}
106
+ onVisibilityChange={handleVisibilityChange}
107
+ />
108
+ );
109
+ }
110
+ ```
111
+
112
+ ### With Required Columns (React)
113
+
114
+ ```tsx
115
+
116
+ const columns: IColumnDefinition[] = [
117
+ { columnId: 'id', name: 'ID', required: true }, // Cannot be hidden
118
+ { columnId: 'name', name: 'Product Name', required: true }, // Cannot be hidden
119
+ { columnId: 'price', name: 'Price' },
120
+ { columnId: 'stock', name: 'Stock' },
121
+ ];
122
+
123
+ function MyApp() {
124
+ // ... (same as above)
125
+ return (
126
+ <ColumnChooser
127
+ columns={columns}
128
+ visibleColumns={visibleColumns}
129
+ onVisibilityChange={handleVisibilityChange}
130
+ />
131
+ );
132
+ }
133
+ ```
134
+
135
+ The "ID" and "Product Name" columns will have disabled checkboxes and cannot be hidden.
136
+
137
+ ## Angular Usage
138
+
139
+ In Angular packages, the component uses `@Input()` and `@Output()` decorators:
140
+
141
+ ```typescript
142
+
143
+ @Component({
144
+ selector: 'app-my-grid',
145
+ standalone: true,
146
+ imports: [ColumnChooserComponent],
147
+ template: `
148
+ <ogrid-column-chooser
149
+ [columns]="columns"
150
+ [visibleColumns]="visibleColumns"
151
+ (onVisibilityChange)="handleVisibilityChange($event)"
152
+ />
153
+ `
154
+ })
155
+ export class MyGridComponent {
156
+ columns: IColumnDefinition[] = [
157
+ { columnId: 'id', name: 'ID', required: true },
158
+ { columnId: 'name', name: 'Product Name' },
159
+ { columnId: 'price', name: 'Price' },
160
+ ];
161
+
162
+ visibleColumns = new Set(['id', 'name', 'price']);
163
+
164
+ handleVisibilityChange(event: { columnKey: string; visible: boolean }) {
165
+ if (event.visible) {
166
+ this.visibleColumns.add(event.columnKey);
167
+ } else {
168
+ this.visibleColumns.delete(event.columnKey);
169
+ }
170
+ this.visibleColumns = new Set(this.visibleColumns); // Trigger change detection
171
+ }
172
+ }
173
+ ```
174
+
175
+ ## Vue Usage
176
+
177
+ In Vue packages, the component accepts props via `v-bind` or shorthand `:`:
178
+
179
+ ```vue
180
+ <template>
181
+ <ColumnChooser
182
+ :columns="columns"
183
+ :visible-columns="visibleColumns"
184
+ @visibility-change="handleVisibilityChange"
185
+ />
186
+ </template>
187
+
188
+ <script setup lang="ts">
189
+
190
+ const columns: IColumnDefinition[] = [
191
+ { columnId: 'id', name: 'ID', required: true },
192
+ { columnId: 'name', name: 'Product Name' },
193
+ { columnId: 'price', name: 'Price' },
194
+ ];
195
+
196
+ const visibleColumns = ref<Set<string>>(new Set(['id', 'name', 'price']));
197
+
198
+ const handleVisibilityChange = (columnKey: string, visible: boolean) => {
199
+ if (visible) {
200
+ visibleColumns.value.add(columnKey);
201
+ } else {
202
+ visibleColumns.value.delete(columnKey);
203
+ }
204
+ visibleColumns.value = new Set(visibleColumns.value); // Trigger reactivity
205
+ };
206
+ </script>
207
+ ```
208
+
209
+ ## Behavior
210
+
211
+ ### Select All / Clear All
212
+
213
+ The dropdown includes two action buttons:
214
+ - **Select All** — Shows all columns (except those marked as `required: false` — these remain hidden)
215
+ - **Clear All** — Hides all optional columns (required columns remain visible)
216
+
217
+ ### Visual Indicator
218
+
219
+ The trigger button shows the current visibility count: `"Column Visibility (3 of 5)"`.
220
+
221
+ ### Checkbox States
222
+
223
+ - **Checked** — Column is visible
224
+ - **Unchecked** — Column is hidden
225
+ - **Disabled + Checked** — Column is required and cannot be hidden
226
+
227
+ ## Accessibility
228
+
229
+ `ColumnChooser` implements WCAG 2.1 AA standards with full keyboard and screen reader support.
230
+
231
+ ### ARIA Attributes
232
+
233
+ ```html
234
+ <button aria-expanded="false" aria-haspopup="listbox">
235
+ Column Visibility (3 of 5)
236
+ </button>
237
+ <div role="dialog" aria-label="Column visibility">
238
+ <input type="checkbox" id="col-name" />
239
+ <label for="col-name">Product Name</label>
240
+ </div>
241
+ ```
242
+
243
+ | Attribute | Element | Purpose |
244
+ |-----------|---------|---------|
245
+ | `aria-expanded` | Trigger button | Indicates dropdown open/closed state (`"true"` / `"false"`) |
246
+ | `aria-haspopup="listbox"` | Trigger button | Indicates the button triggers a listbox |
247
+ | `role="dialog"` | Dropdown | Identifies the dropdown as a modal dialog |
248
+ | `aria-label="Column visibility"` | Dropdown | Provides context for the dialog |
249
+ | `id` / `for` | Checkbox + label | Associates each checkbox with its label |
250
+ | `disabled` | Checkbox | Indicates required columns that cannot be hidden |
251
+
252
+ ### Keyboard Navigation
253
+
254
+ - `Enter` / `Space` (on trigger button) — Open/close dropdown
255
+ - `Tab` / `Shift+Tab` — Navigate between checkboxes and action buttons
256
+ - `Space` — Toggle focused checkbox
257
+ - `Enter` (on action buttons) — Execute "Select All" or "Clear All"
258
+ - `Escape` — Close dropdown
259
+
260
+ ### Focus Management
261
+
262
+ - **Focus trap:** Focus is trapped within the dropdown when open
263
+ - **Focus restoration:** When closing the dropdown, focus returns to the trigger button
264
+ - **Focus visible:** `:focus-visible` styles show 2px solid outline (`--ogrid-accent`)
265
+
266
+ ### Screen Reader Support
267
+
268
+ Screen readers announce:
269
+ - **Trigger button:** "Column Visibility (3 of 5) button, collapsed/expanded"
270
+ - **Checkbox state:** "Product Name checkbox, checked/unchecked"
271
+ - **Required columns:** "ID checkbox, checked, disabled, required column"
272
+ - **Action buttons:** "Select All button", "Clear All button"
273
+
274
+ Tested with NVDA, JAWS, VoiceOver, and Narrator.
275
+
276
+ ### High Contrast Mode
277
+
278
+ - Checkboxes remain visible in high contrast mode
279
+ - Focus indicators use system `Highlight` color
280
+ - Dropdown borders use system `ButtonText` color
281
+
282
+ See the [Accessibility Guide](/docs/guides/accessibility) for complete documentation.
283
+
284
+ ## Styling
285
+
286
+ All UI packages provide default styles matching their design system. Styles are scoped to avoid conflicts.
287
+
288
+ **CSS custom properties** (all packages):
289
+ - `--ogrid-header-bg` — Trigger button and popover background color
290
+ - `--ogrid-border` — Border color
291
+ - `--ogrid-fg` — Foreground text color
292
+
293
+ ## Placement in OGrid
294
+
295
+ The `columnChooser` prop on `OGrid` controls where the column chooser renders:
296
+
297
+ - `true` or `'toolbar'` (default) — Renders in the toolbar strip (recommended)
298
+ - `'sidebar'` — Only available via the sidebar columns panel (no toolbar button)
299
+ - `false` — Hidden entirely (useful when you want full control over visibility)
300
+
301
+ ## Related Components
302
+
303
+ - [DataGridTable](./components-datagrid-table.mdx) — Main grid component
304
+ - [SideBar](./components-sidebar.mdx) — Sidebar with columns panel (alternative placement)
305
+ - [OGrid](./ogrid-props.mdx) — Top-level wrapper that integrates the column chooser
306
+
307
+ ## See Also
308
+
309
+ - [Column Definition](./column-def.mdx#icolumnmeta) — Column metadata reference
310
+ - [Grid API](./grid-api.mdx) — `getColumnState()` and `applyColumnState()` methods
@@ -0,0 +1,363 @@
1
+ ---
2
+ sidebar_position: 11
3
+ title: ColumnHeaderFilter
4
+ ---
5
+
6
+ # ColumnHeaderFilter
7
+
8
+ A column header component that combines sorting and filtering UI. Displays the column name, sort indicator, and filter icon. Clicking the filter icon opens a popover with filter controls (text input, multi-select checkboxes, people picker, or date range).
9
+
10
+ ## Import
11
+
12
+
13
+ <Tabs groupId="framework">
14
+ <TabItem value="react" label="React">
15
+
16
+ ```typescript
17
+ // or
18
+ // or
19
+ ```
20
+
21
+ </TabItem>
22
+ <TabItem value="angular" label="Angular">
23
+
24
+ ```typescript
25
+ // or
26
+ // or
27
+ ```
28
+
29
+ </TabItem>
30
+ <TabItem value="vue" label="Vue">
31
+
32
+ ```typescript
33
+ // or
34
+ // or
35
+ ```
36
+
37
+ </TabItem>
38
+ <TabItem value="js" label="Vanilla JS">
39
+
40
+ ```typescript
41
+ // ColumnHeaderFilter is an internal component in vanilla JS
42
+ ```
43
+
44
+ </TabItem>
45
+ </Tabs>
46
+
47
+ ## Props (React)
48
+
49
+ | Prop | Type | Default | Description |
50
+ |------|------|---------|-------------|
51
+ | `columnKey` | `string` | **Required** | Unique column identifier. |
52
+ | `columnName` | `string` | **Required** | Display name shown in the header. |
53
+ | `filterType` | `ColumnFilterType` | **Required** | Filter type: `'none'`, `'text'`, `'multiSelect'`, `'people'`, or `'date'`. |
54
+ | `isSorted` | `boolean` | `false` | Whether this column is currently sorted. |
55
+ | `isSortedDescending` | `boolean` | `false` | Sort direction (only relevant when `isSorted` is true). |
56
+ | `onSort` | `() => void` | `undefined` | Callback when user clicks the header to sort. |
57
+ | `selectedValues` | `string[]` | `[]` | Selected values for multi-select filter. |
58
+ | `onFilterChange` | `(values: string[]) => void` | `undefined` | Callback when multi-select filter is applied. |
59
+ | `options` | `string[]` | `[]` | Available options for multi-select filter. |
60
+ | `isLoadingOptions` | `boolean` | `false` | Loading state for multi-select options. |
61
+ | `textValue` | `string` | `''` | Current text filter value. |
62
+ | `onTextChange` | `(value: string) => void` | `undefined` | Callback when text filter is applied. |
63
+ | `selectedUser` | `UserLike` | `undefined` | Selected user for people filter. |
64
+ | `onUserChange` | `(user: UserLike \| undefined) => void` | `undefined` | Callback when people filter is applied or cleared. |
65
+ | `peopleSearch` | `(query: string) => Promise<UserLike[]>` | `undefined` | Async search function for people picker. |
66
+ | `dateValue` | `IDateFilterValue` | `undefined` | Current date range filter value. |
67
+ | `onDateChange` | `(value: IDateFilterValue \| undefined) => void` | `undefined` | Callback when date filter is applied or cleared. |
68
+
69
+ ## Filter Types
70
+
71
+ ### Text Filter (`filterType: 'text'`)
72
+
73
+ Shows a text input. The user types a query and clicks "Apply" to filter rows containing the text (case-insensitive).
74
+
75
+ **Required props:** `textValue`, `onTextChange`
76
+
77
+ ### Multi-Select Filter (`filterType: 'multiSelect'`)
78
+
79
+ Shows a searchable list of checkboxes. The user selects one or more values and clicks "Apply" to filter rows matching any selected value.
80
+
81
+ **Required props:** `selectedValues`, `onFilterChange`, `options`
82
+
83
+ **Optional props:** `isLoadingOptions`
84
+
85
+ ### People Filter (`filterType: 'people'`)
86
+
87
+ Shows a people picker with async search. The user types a name or email, selects a person from the results, and clicks "Apply" to filter rows assigned to that person.
88
+
89
+ **Required props:** `selectedUser`, `onUserChange`, `peopleSearch`
90
+
91
+ ### Date Filter (`filterType: 'date'`)
92
+
93
+ Shows a date range picker with "From" and "To" inputs (ISO `YYYY-MM-DD` format). The user selects a date range and clicks "Apply" to filter rows within that range.
94
+
95
+ **Required props:** `dateValue`, `onDateChange`
96
+
97
+ ### No Filter (`filterType: 'none'`)
98
+
99
+ No filter icon is shown. Only the sort indicator is displayed (if the column is sortable).
100
+
101
+ ## Usage
102
+
103
+ ### Text Filter (React)
104
+
105
+ ```tsx
106
+
107
+ function MyHeader() {
108
+ const [textValue, setTextValue] = useState('');
109
+
110
+ return (
111
+ <ColumnHeaderFilter
112
+ columnKey="name"
113
+ columnName="Product Name"
114
+ filterType="text"
115
+ textValue={textValue}
116
+ onTextChange={setTextValue}
117
+ />
118
+ );
119
+ }
120
+ ```
121
+
122
+ ### Multi-Select Filter (React)
123
+
124
+ ```tsx
125
+
126
+ function MyHeader() {
127
+ const [selectedValues, setSelectedValues] = useState<string[]>([]);
128
+ const options = ['Active', 'Pending', 'Completed'];
129
+
130
+ return (
131
+ <ColumnHeaderFilter
132
+ columnKey="status"
133
+ columnName="Status"
134
+ filterType="multiSelect"
135
+ selectedValues={selectedValues}
136
+ onFilterChange={setSelectedValues}
137
+ options={options}
138
+ />
139
+ );
140
+ }
141
+ ```
142
+
143
+ ### People Filter (React)
144
+
145
+ ```tsx
146
+
147
+ function MyHeader() {
148
+ const [selectedUser, setSelectedUser] = useState<UserLike | undefined>();
149
+
150
+ const searchPeople = async (query: string): Promise<UserLike[]> => {
151
+ // Call your user directory API
152
+ const response = await fetch(`/api/users/search?q=${query}`);
153
+ return response.json();
154
+ };
155
+
156
+ return (
157
+ <ColumnHeaderFilter
158
+ columnKey="assignee"
159
+ columnName="Assigned To"
160
+ filterType="people"
161
+ selectedUser={selectedUser}
162
+ onUserChange={setSelectedUser}
163
+ peopleSearch={searchPeople}
164
+ />
165
+ );
166
+ }
167
+ ```
168
+
169
+ ### With Sorting (React)
170
+
171
+ ```tsx
172
+
173
+ function MyHeader() {
174
+ const [sortBy, setSortBy] = useState('name');
175
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc');
176
+
177
+ const handleSort = () => {
178
+ if (sortBy === 'name') {
179
+ setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
180
+ } else {
181
+ setSortBy('name');
182
+ setSortDirection('asc');
183
+ }
184
+ };
185
+
186
+ return (
187
+ <ColumnHeaderFilter
188
+ columnKey="name"
189
+ columnName="Product Name"
190
+ filterType="text"
191
+ isSorted={sortBy === 'name'}
192
+ isSortedDescending={sortDirection === 'desc'}
193
+ onSort={handleSort}
194
+ textValue=""
195
+ onTextChange={() => {}}
196
+ />
197
+ );
198
+ }
199
+ ```
200
+
201
+ ## Angular Usage
202
+
203
+ In Angular packages, the component has the same prop interface but uses `@Input()` decorators:
204
+
205
+ ```typescript
206
+
207
+ @Component({
208
+ selector: 'app-my-header',
209
+ standalone: true,
210
+ imports: [ColumnHeaderFilterComponent],
211
+ template: `
212
+ <ogrid-column-header-filter
213
+ [columnKey]="'status'"
214
+ [columnName]="'Status'"
215
+ [filterType]="'multiSelect'"
216
+ [selectedValues]="selectedValues"
217
+ (onFilterChange)="handleFilterChange($event)"
218
+ [options]="options"
219
+ />
220
+ `
221
+ })
222
+ export class MyHeaderComponent {
223
+ selectedValues: string[] = [];
224
+ options = ['Active', 'Pending', 'Completed'];
225
+
226
+ handleFilterChange(values: string[]) {
227
+ this.selectedValues = values;
228
+ }
229
+ }
230
+ ```
231
+
232
+ ## Vue Usage
233
+
234
+ In Vue packages, the component accepts props via `v-bind` or shorthand `:`:
235
+
236
+ ```vue
237
+ <template>
238
+ <ColumnHeaderFilter
239
+ column-key="status"
240
+ column-name="Status"
241
+ filter-type="multiSelect"
242
+ :selected-values="selectedValues"
243
+ @filter-change="handleFilterChange"
244
+ :options="options"
245
+ />
246
+ </template>
247
+
248
+ <script setup lang="ts">
249
+
250
+ const selectedValues = ref<string[]>([]);
251
+ const options = ['Active', 'Pending', 'Completed'];
252
+
253
+ const handleFilterChange = (values: string[]) => {
254
+ selectedValues.value = values;
255
+ };
256
+ </script>
257
+ ```
258
+
259
+ ## Accessibility
260
+
261
+ `ColumnHeaderFilter` implements WCAG 2.1 AA standards with full keyboard and screen reader support.
262
+
263
+ ### ARIA Attributes
264
+
265
+ ```html
266
+ <th scope="col">
267
+ <button aria-label="Sort by Product Name, currently unsorted">
268
+ Product Name
269
+ </button>
270
+ <button aria-label="Filter Product Name" aria-expanded="false" aria-haspopup="dialog">
271
+
272
+ </button>
273
+ </th>
274
+ ```
275
+
276
+ | Attribute | Element | Purpose |
277
+ |-----------|---------|---------|
278
+ | `scope="col"` | `<th>` | Associates header with its column for screen readers |
279
+ | `aria-label` (sort button) | `<button>` | Describes current sort state: "Sort by X, currently unsorted/ascending/descending" |
280
+ | `aria-label` (filter button) | `<button>` | Describes filter action: "Filter X" |
281
+ | `aria-expanded` | Filter button | Indicates popover open/closed state (`"true"` / `"false"`) |
282
+ | `aria-haspopup="dialog"` | Filter button | Indicates the button triggers a dialog |
283
+ | `role="dialog"` | Filter popover | Identifies the popover as a modal dialog |
284
+ | `aria-label` | Filter popover | Provides context: "Filter Product Name" |
285
+
286
+ ### Keyboard Navigation
287
+
288
+ **Header Interaction:**
289
+ - `Tab` — Move focus to sort button, then filter button
290
+ - `Enter` / `Space` — Activate focused button (toggle sort or open filter)
291
+ - `Shift+Tab` — Move focus backwards
292
+
293
+ **Filter Popover (All Types):**
294
+ - `Escape` — Close popover without applying changes
295
+ - `Tab` / `Shift+Tab` — Navigate inputs and buttons
296
+ - `Enter` (on Apply button) — Apply filter and close popover
297
+
298
+ **Text Filter:**
299
+ - Type to enter filter text
300
+ - `Enter` — Apply filter immediately (no button click needed)
301
+
302
+ **Multi-Select Filter:**
303
+ - `↑` `↓` — Navigate checkbox list
304
+ - `Space` — Toggle focused checkbox
305
+ - `Ctrl+A` — Select all options
306
+ - Type to search options
307
+
308
+ **People Filter:**
309
+ - Type to search people
310
+ - `↓` — Move to search results list
311
+ - `↑` `↓` — Navigate search results
312
+ - `Enter` — Select focused person
313
+ - `Backspace` — Clear selected person
314
+
315
+ **Date Filter:**
316
+ - `Tab` — Move between "From" and "To" inputs
317
+ - Type date in `YYYY-MM-DD` format
318
+ - Date picker (if supported): Arrow keys to navigate calendar
319
+
320
+ ### Focus Management
321
+
322
+ - **Focus trap:** Focus is trapped within the filter popover when open
323
+ - **Focus restoration:** When closing the popover, focus returns to the filter button
324
+ - **Focus visible:** `:focus-visible` styles show 2px solid outline (`--ogrid-accent`) on keyboard navigation
325
+
326
+ ### Screen Reader Support
327
+
328
+ Screen readers announce:
329
+ - **Header navigation:** "Product Name column header, sortable"
330
+ - **Sort state:** "Sorted by Product Name, ascending"
331
+ - **Filter button:** "Filter Product Name button, collapsed/expanded"
332
+ - **Filter applied:** "Filter applied: Status equals Active"
333
+ - **Filter cleared:** "Filter cleared from Status column"
334
+
335
+ Tested with NVDA, JAWS, VoiceOver, and Narrator.
336
+
337
+ ### High Contrast Mode
338
+
339
+ - Filter icons remain visible in high contrast mode
340
+ - Focus indicators use system `Highlight` color
341
+ - Popover borders use system `ButtonText` color
342
+
343
+ See the [Accessibility Guide](/docs/guides/accessibility) for complete documentation.
344
+
345
+ ## Styling
346
+
347
+ All UI packages provide default styles matching their design system (Radix UI, Fluent UI, Material UI, PrimeNG, Vuetify, PrimeVue). Styles are scoped to avoid conflicts.
348
+
349
+ **CSS custom properties** (all packages):
350
+ - `--ogrid-header-bg` — Header background color
351
+ - `--ogrid-border` — Border color
352
+ - `--ogrid-fg` — Foreground text color
353
+
354
+ ## Related Components
355
+
356
+ - [DataGridTable](./components-datagrid-table.mdx) — Main grid component that renders column headers
357
+ - [ColumnChooser](./components-column-chooser.mdx) — Column visibility dropdown
358
+ - [Types: FilterValue](./types.mdx#filtervalue) — Filter value discriminated union
359
+
360
+ ## See Also
361
+
362
+ - [Column Definition](./column-def.mdx#icolumnfilterdef) — Filter configuration reference
363
+ - [Filtering Feature Guide](/docs/features/filtering) — Complete filtering documentation