@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,550 @@
1
+ ---
2
+ sidebar_position: 8
3
+ title: Accessibility
4
+ ---
5
+
6
+ # Accessibility
7
+
8
+ OGrid is built with accessibility as a core principle, meeting WCAG 2.1 AA standards. All components support keyboard navigation, screen readers, and high contrast modes.
9
+
10
+ ## WCAG 2.1 AA Compliance
11
+
12
+ OGrid implements the following WCAG 2.1 AA guidelines:
13
+
14
+ ### Perceivable
15
+
16
+ - **1.3.1 Info and Relationships** — Semantic HTML (`<table>`, `<thead>`, `<tbody>`, `<th>`, `<td>`) with proper ARIA roles
17
+ - **1.4.1 Use of Color** — Focus indicators use both color and visible outlines (2px solid)
18
+ - **1.4.3 Contrast (Minimum)** — All text and interactive elements meet 4.5:1 contrast ratio
19
+ - **1.4.11 Non-text Contrast** — Focus indicators and UI components meet 3:1 contrast
20
+
21
+ ### Operable
22
+
23
+ - **2.1.1 Keyboard** — All functionality available via keyboard
24
+ - **2.1.2 No Keyboard Trap** — Focus can always escape modal dialogs and popovers
25
+ - **2.4.3 Focus Order** — Logical tab order through interactive elements
26
+ - **2.4.7 Focus Visible** — `:focus-visible` styles on all interactive elements
27
+
28
+ ### Understandable
29
+
30
+ - **3.2.1 On Focus** — No unexpected context changes when elements receive focus
31
+ - **3.2.2 On Input** — No automatic context changes during user input
32
+ - **3.3.2 Labels or Instructions** — All form controls have associated `<label>` elements
33
+
34
+ ### Robust
35
+
36
+ - **4.1.2 Name, Role, Value** — All UI components use proper ARIA attributes
37
+ - **4.1.3 Status Messages** — ARIA live regions announce dynamic content changes
38
+
39
+ ## Keyboard Navigation
40
+
41
+ OGrid provides Excel-style keyboard navigation for all grid interactions.
42
+
43
+ ### Arrow Key Navigation
44
+
45
+ | Key | Action |
46
+ |-----|--------|
47
+ | `↑` `↓` `←` `→` | Move active cell one cell in the direction pressed |
48
+ | `Ctrl+↑` / `Ctrl+↓` | Jump to first/last row in current column |
49
+ | `Ctrl+←` / `Ctrl+→` | Jump to first/last column in current row |
50
+ | `Home` | Jump to first column in current row |
51
+ | `End` | Jump to last column in current row |
52
+ | `Ctrl+Home` | Jump to first cell (top-left) |
53
+ | `Ctrl+End` | Jump to last cell (bottom-right) |
54
+
55
+ ### Selection
56
+
57
+ | Key | Action |
58
+ |-----|--------|
59
+ | `Shift+↑` `↓` `←` `→` | Extend cell selection range |
60
+ | `Shift+Home` | Extend selection to first column |
61
+ | `Shift+End` | Extend selection to last column |
62
+ | `Shift+Ctrl+Home` | Extend selection to top-left corner |
63
+ | `Shift+Ctrl+End` | Extend selection to bottom-right corner |
64
+ | `Ctrl+A` | Select all cells |
65
+ | `Space` (on checkbox column) | Toggle row selection |
66
+
67
+ ### Editing
68
+
69
+ | Key | Action |
70
+ |-----|--------|
71
+ | `Enter` | Start editing active cell (if editable) |
72
+ | `F2` | Start editing active cell (if editable) |
73
+ | `Escape` | Cancel editing and revert changes |
74
+ | `Enter` (while editing) | Commit changes and move down |
75
+ | `Tab` (while editing) | Commit changes and move right |
76
+ | `Shift+Tab` (while editing) | Commit changes and move left |
77
+
78
+ ### Clipboard
79
+
80
+ | Key | Action |
81
+ |-----|--------|
82
+ | `Ctrl+C` / `Cmd+C` | Copy selected cells |
83
+ | `Ctrl+X` / `Cmd+X` | Cut selected cells |
84
+ | `Ctrl+V` / `Cmd+V` | Paste clipboard content |
85
+ | `Delete` | Clear selected cells |
86
+
87
+ ### Undo/Redo
88
+
89
+ | Key | Action |
90
+ |-----|--------|
91
+ | `Ctrl+Z` / `Cmd+Z` | Undo last edit |
92
+ | `Ctrl+Y` / `Cmd+Shift+Z` | Redo last undone edit |
93
+
94
+ ### Context Menu
95
+
96
+ | Key | Action |
97
+ |-----|--------|
98
+ | `Shift+F10` | Open context menu for active cell |
99
+ | `Escape` | Close context menu |
100
+ | `↑` `↓` | Navigate menu items |
101
+ | `Enter` | Execute selected menu item |
102
+
103
+ ### Column Headers
104
+
105
+ | Key | Action |
106
+ |-----|--------|
107
+ | `Enter` / `Space` | Toggle sort on focused column header |
108
+ | `Tab` | Move focus to next interactive element (sort/filter buttons) |
109
+ | `Shift+Tab` | Move focus to previous interactive element |
110
+
111
+ ### Pagination
112
+
113
+ | Key | Action |
114
+ |-----|--------|
115
+ | `Tab` | Navigate between pagination buttons and page size dropdown |
116
+ | `Enter` / `Space` | Activate focused button |
117
+ | `←` `→` | Navigate page number buttons |
118
+
119
+ ### Column Chooser
120
+
121
+ | Key | Action |
122
+ |-----|--------|
123
+ | `Enter` / `Space` | Open/close column chooser dropdown |
124
+ | `↑` `↓` | Navigate column list |
125
+ | `Space` | Toggle column visibility |
126
+ | `Escape` | Close dropdown |
127
+
128
+ ### Filters
129
+
130
+ | Key | Action |
131
+ |-----|--------|
132
+ | `Enter` / `Space` | Open filter popover |
133
+ | `Tab` | Navigate filter inputs |
134
+ | `Enter` | Apply filter |
135
+ | `Escape` | Close filter popover |
136
+
137
+ ## ARIA Attributes
138
+
139
+ OGrid uses comprehensive ARIA attributes for screen reader support.
140
+
141
+ ### DataGridTable
142
+
143
+ ```html
144
+ <div role="grid" aria-label="Product catalog" aria-rowcount="1000">
145
+ <table>
146
+ <thead>
147
+ <tr role="row">
148
+ <th role="columnheader" aria-sort="ascending" scope="col">
149
+ Product Name
150
+ </th>
151
+ </tr>
152
+ </thead>
153
+ <tbody>
154
+ <tr role="row" aria-rowindex="1">
155
+ <td role="gridcell" tabindex="-1">Widget</td>
156
+ </tr>
157
+ </tbody>
158
+ </table>
159
+ </div>
160
+ ```
161
+
162
+ | Attribute | Element | Purpose |
163
+ |-----------|---------|---------|
164
+ | `role="grid"` | Grid wrapper | Identifies the grid container |
165
+ | `role="row"` | `<tr>` | Identifies table rows |
166
+ | `role="columnheader"` | `<th>` | Identifies column headers |
167
+ | `role="gridcell"` | `<td>` | Identifies data cells |
168
+ | `aria-label` | Grid wrapper | Provides accessible name for the grid |
169
+ | `aria-rowcount` | Grid wrapper | Total number of rows (server-side pagination) |
170
+ | `aria-rowindex` | `<tr>` | Row's position in the full dataset (1-indexed) |
171
+ | `aria-sort` | `<th>` | Current sort state (`"ascending"`, `"descending"`, `"none"`) |
172
+ | `aria-colindex` | `<th>`, `<td>` | Column's position (1-indexed) |
173
+ | `tabindex="-1"` | `<td>` | Enables programmatic focus for keyboard navigation |
174
+
175
+ ### StatusBar
176
+
177
+ ```html
178
+ <div role="status" aria-live="polite">
179
+ <span>Rows: 1,000</span>
180
+ <span>Selected: 5</span>
181
+ </div>
182
+ ```
183
+
184
+ | Attribute | Purpose |
185
+ |-----------|---------|
186
+ | `role="status"` | Identifies status information |
187
+ | `aria-live="polite"` | Announces changes when user is idle (non-intrusive) |
188
+
189
+ ### PaginationControls
190
+
191
+ ```html
192
+ <nav role="navigation" aria-label="Pagination">
193
+ <button aria-label="First page" aria-disabled="true">«</button>
194
+ <button aria-label="Previous page" aria-disabled="true">‹</button>
195
+ <button aria-label="Page 1" aria-current="page">1</button>
196
+ <button aria-label="Page 2">2</button>
197
+ <button aria-label="Next page">›</button>
198
+ <button aria-label="Last page">»</button>
199
+ </nav>
200
+ ```
201
+
202
+ | Attribute | Purpose |
203
+ |-----------|---------|
204
+ | `role="navigation"` | Identifies pagination controls |
205
+ | `aria-label="Pagination"` | Provides context for screen readers |
206
+ | `aria-label` (buttons) | Descriptive labels for icon-only buttons |
207
+ | `aria-current="page"` | Identifies the current page |
208
+ | `aria-disabled` | Indicates disabled state |
209
+
210
+ ### ColumnChooser
211
+
212
+ ```html
213
+ <button aria-expanded="false" aria-haspopup="listbox">
214
+ Column Visibility (3 of 5)
215
+ </button>
216
+ <div role="dialog" aria-label="Column visibility">
217
+ <input type="checkbox" id="col-name" />
218
+ <label for="col-name">Product Name</label>
219
+ </div>
220
+ ```
221
+
222
+ | Attribute | Purpose |
223
+ |-----------|---------|
224
+ | `aria-expanded` | Indicates dropdown open/closed state |
225
+ | `aria-haspopup="listbox"` | Indicates the button triggers a listbox |
226
+ | `role="dialog"` | Identifies the dropdown as a dialog |
227
+ | `aria-label="Column visibility"` | Provides context for the dialog |
228
+
229
+ ### ColumnHeaderFilter
230
+
231
+ ```html
232
+ <th scope="col">
233
+ <button aria-label="Sort by Product Name, currently unsorted">
234
+ Product Name
235
+ </button>
236
+ <button aria-label="Filter Product Name" aria-expanded="false">
237
+
238
+ </button>
239
+ </th>
240
+ ```
241
+
242
+ | Attribute | Purpose |
243
+ |-----------|---------|
244
+ | `scope="col"` | Associates header with its column |
245
+ | `aria-label` (sort button) | Describes current sort state |
246
+ | `aria-label` (filter button) | Describes filter action |
247
+ | `aria-expanded` | Indicates filter popover open/closed state |
248
+
249
+ ### Editable Cells
250
+
251
+ ```html
252
+ <td role="gridcell" aria-readonly="false" tabindex="-1">
253
+ <input aria-label="Edit Product Name" />
254
+ </td>
255
+ ```
256
+
257
+ | Attribute | Purpose |
258
+ |-----------|---------|
259
+ | `aria-readonly="false"` | Indicates cell is editable |
260
+ | `aria-label` (input) | Provides context for screen readers |
261
+
262
+ ## Screen Reader Support
263
+
264
+ OGrid is tested with the following screen readers:
265
+
266
+ - **NVDA** (Windows) — Latest version
267
+ - **JAWS** (Windows) — Latest version
268
+ - **VoiceOver** (macOS) — Built-in
269
+ - **Narrator** (Windows) — Built-in
270
+ - **TalkBack** (Android) — Built-in
271
+
272
+ ### Announcements
273
+
274
+ Screen readers announce the following information:
275
+
276
+ #### Grid Navigation
277
+
278
+ - **Cell activation:** "Product Name, cell, row 1, column 2"
279
+ - **Sort change:** "Sorted by Product Name, ascending"
280
+ - **Filter applied:** "Filtered by Status, 3 results"
281
+ - **Selection:** "5 rows selected"
282
+
283
+ #### Editing
284
+
285
+ - **Edit mode:** "Editing Product Name, row 1, column 2"
286
+ - **Value changed:** "Product Name changed from Widget to Gadget"
287
+ - **Validation error:** "Invalid value: Price must be a positive number"
288
+
289
+ #### Pagination
290
+
291
+ - **Page change:** "Showing 21 to 40 of 250 rows, page 2 of 13"
292
+ - **Page size change:** "Page size changed to 50 rows per page"
293
+
294
+ #### Column Visibility
295
+
296
+ - **Column hidden:** "Product Name column hidden"
297
+ - **Column shown:** "Product Name column shown"
298
+
299
+ ## Focus Management
300
+
301
+ OGrid implements advanced focus management for optimal keyboard experience.
302
+
303
+ ### Focus Visible
304
+
305
+ All interactive elements use `:focus-visible` (not `:focus`) to show focus indicators only when navigating via keyboard, not when clicking with a mouse.
306
+
307
+ ```scss
308
+ .dataTable tbody tr {
309
+ outline: none;
310
+
311
+ &:focus-visible {
312
+ outline: 2px solid var(--ogrid-accent, #0078d4);
313
+ outline-offset: -2px;
314
+ }
315
+ }
316
+ ```
317
+
318
+ ### Focus Trap
319
+
320
+ Modal dialogs and popovers trap focus within their boundaries:
321
+ - `Tab` cycles through interactive elements inside the dialog
322
+ - `Shift+Tab` cycles backwards
323
+ - `Escape` closes the dialog and returns focus to the trigger element
324
+
325
+ ### Focus Restoration
326
+
327
+ When closing dialogs, popovers, or exiting edit mode:
328
+ - Focus returns to the element that triggered the action
329
+ - Active cell focus is restored after pagination or sorting
330
+
331
+ ## High Contrast Mode
332
+
333
+ OGrid supports Windows High Contrast Mode and other forced color schemes.
334
+
335
+ ### Custom Properties
336
+
337
+ All colors use CSS custom properties with fallbacks:
338
+
339
+ ```css
340
+ --ogrid-bg: #ffffff; /* Background */
341
+ --ogrid-fg: #242424; /* Foreground text */
342
+ --ogrid-border: #e0e0e0; /* Borders */
343
+ --ogrid-accent: #0078d4; /* Focus indicators, primary actions */
344
+ --ogrid-bg-subtle: #f3f2f1; /* Header background */
345
+ ```
346
+
347
+ ### High Contrast Support
348
+
349
+ In high contrast mode:
350
+ - Focus indicators use system colors (`Highlight`, `HighlightText`)
351
+ - Borders use system colors (`ButtonText`, `GrayText`)
352
+ - Icons and text remain visible
353
+
354
+ ## Accessible Usage Examples
355
+
356
+ ### Basic Accessible Grid
357
+
358
+ ```tsx
359
+
360
+ function AccessibleGrid() {
361
+ return (
362
+ <OGrid
363
+ data={products}
364
+ columns={columns}
365
+ getRowId={(item) => item.id}
366
+ aria-label="Product catalog"
367
+ rowSelection="multiple"
368
+ editable={true}
369
+ />
370
+ );
371
+ }
372
+ ```
373
+
374
+ ### With Descriptive Labels
375
+
376
+ ```tsx
377
+
378
+ function GridWithLabels() {
379
+ return (
380
+ <div>
381
+ <h2 id="product-grid-heading">Product Catalog</h2>
382
+ <p id="product-grid-description">
383
+ Browse and manage your product inventory. Use arrow keys to navigate,
384
+ Enter to edit, and Space to select rows.
385
+ </p>
386
+ <OGrid
387
+ data={products}
388
+ columns={columns}
389
+ getRowId={(item) => item.id}
390
+ aria-labelledby="product-grid-heading"
391
+ aria-describedby="product-grid-description"
392
+ />
393
+ </div>
394
+ );
395
+ }
396
+ ```
397
+
398
+ ### Announcing Status Changes
399
+
400
+ ```tsx
401
+
402
+ function GridWithAnnouncements() {
403
+ const [announcement, setAnnouncement] = useState('');
404
+
405
+ const handleSelectionChange = (event) => {
406
+ const count = event.selectedRowIds.length;
407
+ setAnnouncement(`${count} ${count === 1 ? 'row' : 'rows'} selected`);
408
+ };
409
+
410
+ return (
411
+ <>
412
+ <div role="status" aria-live="polite" className="sr-only">
413
+ {announcement}
414
+ </div>
415
+ <OGrid
416
+ data={products}
417
+ columns={columns}
418
+ getRowId={(item) => item.id}
419
+ rowSelection="multiple"
420
+ onSelectionChange={handleSelectionChange}
421
+ />
422
+ </>
423
+ );
424
+ }
425
+ ```
426
+
427
+ ### Screen Reader Only Text
428
+
429
+ Use a `.sr-only` class for screen reader only content:
430
+
431
+ ```css
432
+ .sr-only {
433
+ position: absolute;
434
+ width: 1px;
435
+ height: 1px;
436
+ padding: 0;
437
+ margin: -1px;
438
+ overflow: hidden;
439
+ clip: rect(0, 0, 0, 0);
440
+ white-space: nowrap;
441
+ border-width: 0;
442
+ }
443
+ ```
444
+
445
+ ## Testing Accessibility
446
+
447
+ ### Automated Testing
448
+
449
+ Use automated accessibility testing tools:
450
+
451
+ ```bash
452
+ # Install axe-core for automated testing
453
+ npm install --save-dev @axe-core/react
454
+
455
+ # Install jest-axe for Jest integration
456
+ npm install --save-dev jest-axe
457
+ ```
458
+
459
+ ```tsx
460
+
461
+ expect.extend(toHaveNoViolations);
462
+
463
+ test('OGrid has no accessibility violations', async () => {
464
+ const { container } = render(
465
+ <OGrid
466
+ data={products}
467
+ columns={columns}
468
+ getRowId={(item) => item.id}
469
+ aria-label="Product catalog"
470
+ />
471
+ );
472
+
473
+ const results = await axe(container);
474
+ expect(results).toHaveNoViolations();
475
+ });
476
+ ```
477
+
478
+ ### Manual Testing
479
+
480
+ 1. **Keyboard Navigation**
481
+ - Disconnect your mouse
482
+ - Navigate the entire grid using only keyboard
483
+ - Verify all features are accessible
484
+
485
+ 2. **Screen Reader Testing**
486
+ - Enable VoiceOver (macOS: `Cmd+F5`) or NVDA (Windows)
487
+ - Navigate the grid and verify announcements
488
+ - Test editing, filtering, and selection
489
+
490
+ 3. **High Contrast Mode**
491
+ - Windows: `Alt+Left Shift+Print Screen`
492
+ - Verify all content is visible
493
+ - Check focus indicators are clear
494
+
495
+ 4. **Zoom Testing**
496
+ - Zoom to 200% (`Ctrl++` or `Cmd++`)
497
+ - Verify layout remains usable
498
+ - No horizontal scrolling on text content
499
+
500
+ ### Checklist
501
+
502
+ Use this checklist when building accessible grids:
503
+
504
+ - [ ] Grid has `aria-label` or `aria-labelledby`
505
+ - [ ] All interactive elements are keyboard accessible
506
+ - [ ] Focus indicators are visible (`:focus-visible`)
507
+ - [ ] Column headers have `scope="col"`
508
+ - [ ] Sorted columns have `aria-sort` attribute
509
+ - [ ] Edit mode inputs have descriptive `aria-label`
510
+ - [ ] Status changes are announced (ARIA live regions)
511
+ - [ ] High contrast mode is supported
512
+ - [ ] Tested with screen reader
513
+ - [ ] Automated accessibility tests pass
514
+
515
+ ## Known Limitations
516
+
517
+ ### Virtual Scrolling
518
+
519
+ When virtual scrolling is enabled (`virtualScroll.enabled: true`), screen readers may not announce the total row count accurately because only visible rows are rendered in the DOM. Use `aria-rowcount` on the grid wrapper to communicate the full dataset size.
520
+
521
+ ### Large Datasets
522
+
523
+ For grids with 10,000+ rows, consider server-side pagination instead of client-side filtering to improve screen reader performance.
524
+
525
+ ### Custom Cell Renderers
526
+
527
+ When using custom `renderCell` functions, ensure your custom markup:
528
+ - Includes appropriate ARIA attributes
529
+ - Maintains keyboard navigability
530
+ - Announces changes to screen readers
531
+
532
+ ## Resources
533
+
534
+ - [WCAG 2.1 Guidelines](https://www.w3.org/WAI/WCAG21/quickref/)
535
+ - [ARIA Authoring Practices Guide - Grid Pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/)
536
+ - [WebAIM Screen Reader Testing](https://webaim.org/articles/screenreader_testing/)
537
+ - [axe DevTools Browser Extension](https://www.deque.com/axe/devtools/)
538
+
539
+ ## Support
540
+
541
+ If you encounter accessibility issues or have suggestions for improvements:
542
+
543
+ 1. Check the [GitHub Issues](https://github.com/alaarab/ogrid/issues) for known issues
544
+ 2. Report new issues with:
545
+ - Browser and screen reader versions
546
+ - Steps to reproduce
547
+ - Expected vs. actual behavior
548
+ 3. Tag issues with `accessibility` label
549
+
550
+ We're committed to maintaining WCAG 2.1 AA compliance and improving accessibility based on user feedback.
@@ -0,0 +1,153 @@
1
+ ---
2
+ sidebar_position: 1
3
+ title: Controlled vs Uncontrolled
4
+ description: Choose between letting OGrid manage state internally or owning it yourself.
5
+ ---
6
+
7
+ # Controlled vs Uncontrolled
8
+
9
+ OGrid supports both **uncontrolled** and **controlled** state patterns for every stateful feature -- sorting, filtering, pagination, column visibility, row selection, and column order. You can also mix and match, controlling some features while leaving others to the grid.
10
+
11
+ ## Uncontrolled (Zero Config)
12
+
13
+ In uncontrolled mode, OGrid manages all state internally. Just pass your columns and data:
14
+
15
+ ```tsx
16
+
17
+ const columns = [
18
+ { columnId: 'name', name: 'Name', sortable: true },
19
+ { columnId: 'email', name: 'Email', filterable: { type: 'text' as const } },
20
+ { columnId: 'role', name: 'Role' },
21
+ ];
22
+
23
+ function App() {
24
+ return (
25
+ <OGrid
26
+ columns={columns}
27
+ data={people}
28
+ getRowId={(item) => item.id}
29
+ defaultPageSize={25}
30
+ defaultSortBy="name"
31
+ defaultSortDirection="asc"
32
+ />
33
+ );
34
+ }
35
+ ```
36
+
37
+ The grid handles sorting, filtering, pagination, and everything else on its own. Use the `default*` props to set initial values.
38
+
39
+ ## Controlled (You Own the State)
40
+
41
+ In controlled mode, you pass the current value and an `onChange` callback for each feature you want to control. This is useful when you need to sync grid state with a URL, persist it to storage, or coordinate with other components.
42
+
43
+ ```tsx
44
+
45
+ function App() {
46
+ const [page, setPage] = useState(1);
47
+ const [pageSize, setPageSize] = useState(25);
48
+ const [sort, setSort] = useState({ field: 'name', direction: 'asc' as const });
49
+ const [filters, setFilters] = useState<IFilters>({});
50
+
51
+ // Sync to URL, localStorage, or server on every change
52
+ const handleFiltersChange = (newFilters: IFilters) => {
53
+ setFilters(newFilters);
54
+ saveToUrl(newFilters);
55
+ };
56
+
57
+ return (
58
+ <OGrid
59
+ columns={columns}
60
+ data={people}
61
+ getRowId={(item) => item.id}
62
+ page={page}
63
+ onPageChange={setPage}
64
+ pageSize={pageSize}
65
+ onPageSizeChange={setPageSize}
66
+ sort={sort}
67
+ onSortChange={setSort}
68
+ filters={filters}
69
+ onFiltersChange={handleFiltersChange}
70
+ />
71
+ );
72
+ }
73
+ ```
74
+
75
+ ## Partial Control
76
+
77
+ You do not have to control everything. Control only the features you need -- the rest stays uncontrolled:
78
+
79
+ ```tsx
80
+ function App() {
81
+ // Only control sort; filters, pagination, etc. are managed by the grid
82
+ const [sort, setSort] = useState({ field: 'name', direction: 'asc' as const });
83
+
84
+ return (
85
+ <OGrid
86
+ columns={columns}
87
+ data={people}
88
+ getRowId={(item) => item.id}
89
+ sort={sort}
90
+ onSortChange={setSort}
91
+ defaultPageSize={50}
92
+ />
93
+ );
94
+ }
95
+ ```
96
+
97
+ ## Controllable Prop Pairs
98
+
99
+ Every stateful feature follows the same pattern: a value prop and an `onChange` callback. When both are provided, the grid operates in controlled mode for that feature. When neither is provided, the grid manages it internally.
100
+
101
+ | Feature | Value Prop | Callback Prop | Default Prop |
102
+ |---------|-----------|---------------|-------------|
103
+ | Sort | `sort` | `onSortChange` | `defaultSortBy`, `defaultSortDirection` |
104
+ | Filters | `filters` | `onFiltersChange` | -- |
105
+ | Page | `page` | `onPageChange` | -- |
106
+ | Page size | `pageSize` | `onPageSizeChange` | `defaultPageSize` |
107
+ | Visible columns | `visibleColumns` | `onVisibleColumnsChange` | -- |
108
+ | Selected rows | `selectedRows` | `onSelectionChange` | -- |
109
+ | Column order | `columnOrder` | `onColumnOrderChange` | -- |
110
+
111
+ :::tip
112
+ When using controlled mode, always pass **both** the value and the callback. Passing only the value without a callback will lock the feature in its initial state, since OGrid will not be able to update it.
113
+ :::
114
+
115
+ ## Imperative API
116
+
117
+ For cases where you need to read or set state programmatically (e.g., a "Reset Filters" button), use the grid API ref:
118
+
119
+ ```tsx
120
+
121
+ function App() {
122
+ const gridRef = useRef<IOGridApi<Person>>(null);
123
+
124
+ const handleReset = () => {
125
+ gridRef.current?.setFilterModel({});
126
+ gridRef.current?.deselectAll();
127
+ };
128
+
129
+ return (
130
+ <>
131
+ <button onClick={handleReset}>Reset</button>
132
+ <OGrid
133
+ ref={gridRef}
134
+ columns={columns}
135
+ data={people}
136
+ getRowId={(item) => item.id}
137
+ />
138
+ </>
139
+ );
140
+ }
141
+ ```
142
+
143
+ The API ref works in both controlled and uncontrolled mode. See the [Grid API reference](../api/grid-api) for the full list of methods.
144
+
145
+ ## When to Use Which
146
+
147
+ | Scenario | Recommendation |
148
+ |----------|---------------|
149
+ | Simple table, no external state needed | Uncontrolled |
150
+ | URL-driven filters or sort | Controlled (filters, sort) |
151
+ | Persist column layout to localStorage | Controlled (visibleColumns, columnOrder) + `getColumnState()` |
152
+ | Server-side data with `dataSource` | Controlled or uncontrolled -- both work with `dataSource` |
153
+ | Coordinate multiple grids | Controlled (shared state between grids) |