Accessibility
Every family follows a WAI-ARIA Authoring Practices pattern where one exists, works from the keyboard alone, announces what changes, and respects forced colors, reduced motion and right-to-left text. Both render layers share one implementation of each, so what is true below is true in Angular and in React. The criterion-by-criterion view is the conformance report.
Patterns per family
| Component | Pattern | Keyboard covered by |
|---|---|---|
| Data grid | APG grid; treegrid when grouped or with detail rows | grid-keyboard-drag.spec.ts , selection.spec.ts , editing.spec.ts |
| Tree list | APG treegrid | tree-list-keyboard-drag.spec.ts |
| Pivot grid | APG grid (one tab stop) + reorderable field chips | pivot-keyboard.spec.ts |
| Select box, tag box, autocomplete | APG combobox + listbox | select-box.spec.ts , list-editors-g4b.spec.ts |
| Tabs | APG tabs | tabs.spec.ts |
| Tree view | APG treeview | tree-view.spec.ts , tree-view-depth.spec.ts |
| Menubar, context menu, drop-down button | APG menubar / menu / menu button | menubar.spec.ts , context-menu.spec.ts |
| Speed dial (FAB) | APG menu button | fab.spec.ts |
| Modal, action sheet | Modal dialog with focus containment | overlay.spec.ts , action-sheet.spec.ts |
| Accordion, panel bar, expansion panel | APG accordion / disclosure | accordion.spec.ts |
| Slider, range slider | APG slider | slider.spec.ts |
| Kanban | Keyboard card moves between columns, announced | kanban.spec.ts |
| BPMN editor | role="application" canvas with its own key map | bpmn.spec.ts |
Keyboard maps
Generated from the API reference tables, so they cannot disagree with the component pages.
OgeSpeedDial — Keyboard (WAI-ARIA APG menu button)
@oge-ui/buttons
| Key or item | Scope | Behaviour |
|---|---|---|
| Enter / Space / click | FAB | Toggles the dial; opening moves focus to the first enabled action. |
| Arrow along the dial / back | FAB | Opens with focus on the first (nearest) / last action ( ogeSpeedDialToggleKey ). |
| Arrows · Home · End | action | Move along the dial axis and wrap, skipping disabled actions ( ogeSpeedDialItemKey , ogeSpeedDialNavIndex ); horizontal dials mirror in RTL. |
| Escape / Tab | action | Escape closes and returns focus to the FAB; Tab closes and lets focus move on. |
OgePanelBar — Keyboard & accessibility
@oge-ui/layout
| Key or item | Scope | Behaviour |
|---|---|---|
| APG disclosure, not treeview | — | Kendo renders its PanelBar as role="tree" , but a tree may own nothing but tree items — and panel bar groups may hold free content. So every header is a real <button> in the Tab sequence ( aria-expanded + aria-controls on groups, aria-current on the selected leaf), collapsed groups are inert , and Up/Down/Home/End plus Right/Left (expand-or-enter / collapse-or-parent, mirrored in RTL) are layered on top. Collapsing a group that holds focus hands focus to its header. |
OgeExpansionPanel — Keyboard & accessibility
@oge-ui/layout
| Key or item | Scope | Behaviour |
|---|---|---|
| APG disclosure | — | The title is a <button aria-expanded aria-controls> inside a heading; Enter / Space toggle it natively, the body is role="region" labelled by the header and inert while collapsed. Collapsing a panel that holds focus hands focus back to the header. The pipeline is runOgeExpansionToggle in @oge-ui/behavior , shared with the panel bar. |
OgeTileLayout — Keyboard
@oge-ui/layout
| Key or item | Scope | Behaviour |
|---|---|---|
| Arrow keys / Home / End | focus | Move focus between tiles (one roving tab stop; ↑/↓ go to the closest tile in the row above / below). Content inside a tile keeps its own Tab order, and the tile keys only act while the tile itself is focused. |
| Ctrl+← / Ctrl+→ | move | Move the focused tile one position earlier / later (mirrored in RTL). ⌘ works as Ctrl. |
| Ctrl+↑ / Ctrl+↓ | move | Move the focused tile to the position of the tile above / below. |
| Ctrl+Shift+← / Ctrl+Shift+→ | resize | Shrink / grow the column span (mirrored in RTL), within the tile’s bounds. |
| Ctrl+Shift+↑ / Ctrl+Shift+↓ | resize | Shrink / grow the row span. |
| Escape | cancel | Cancels a pointer drag or resize in progress. |
OgeTreeView — Keyboard (WAI-ARIA APG treeview)
@oge-ui/navigation
| Key or item | Scope | Behaviour |
|---|---|---|
| Down / Up Arrow | navigation | Moves focus over the visible nodes, skipping disabled ones. Trees do not wrap at the ends. |
| Right Arrow | navigation | Opens a collapsed parent; on an open parent moves to its first child; no-op on a leaf. |
| Left Arrow | navigation | Closes an open parent; otherwise moves focus to the parent node. |
| Home / End | navigation | Moves to the first / last visible node. |
| Enter | activation | Toggles a parent, or selects a leaf when a selection mode is set. |
| Space | selection | Toggles selection on the focused node. Shift+Space selects the contiguous range. |
| Printable characters | type-ahead | Moves focus to the next node whose label starts with the typed prefix, accent-insensitively. |
| * | expansion | Expands every sibling at the focused level. |
| Ctrl+A, Shift+Arrow, Ctrl+Shift+Home/End | multi-select | Select all, extend by one, and range-select to the start/end — the APG "recommended" model, so plain navigation needs no modifier. |
| F2 | editing | Opens the label editor ( allowEditing ); inside it Enter commits, Escape cancels and the focus returns to the node. Advertised with aria-keyshortcuts . |
| Ctrl+X, Ctrl+V, Ctrl+Shift+V | move | The keyboard twin of drag & drop ( allowDragging ): cut the focused node, then paste it into (or, with Shift, after) the focused target — in this tree or another of the dragGroup . Escape abandons the cut; each step is announced through the live region. |
OgePivotGrid — Keyboard (WAI-ARIA APG grid + field chips)
@oge-ui/pivot
| Key or item | Scope | Behaviour |
|---|---|---|
| Tab | grid | The matrix is one APG grid with a single tab stop shared by column headers, row headers and value cells (the first value cell until something is focused). |
| Arrow keys | grid | Move between headers and value cells; a spanning column header is one stop, and Down out of it keeps the column you came from. Left/Right are mirrored in RTL. |
| Home / End · Ctrl+Home / Ctrl+End | grid | First / last cell of the row · first column header / last value cell of the grid. |
| Enter / Space (header) | grid | Expands or collapses an expandable row or column header. |
| Shift+F10 / ContextMenu (header) | grid | Opens the header menu (sort, sort by summary, filter, remove, expand/collapse all, field chooser) — the keyboard right-click. |
| Enter / Space / Shift+F10 (field chip) | field panel + chooser | Every field chip is a focusable role="button" with aria-haspopup="menu" ; these keys (and right-click) open its field menu: Move left / Move right, Move to Filters / Rows / Columns / Values, Remove field, and on a measure the summary-type and display-mode items. The single-pointer alternative to dragging (WCAG 2.5.7). |
| Ctrl+Left / Ctrl+Right (field chip) | field panel + chooser | Reorders the field within its area (mirrored in RTL); the new position is announced in a polite live region. |
| Ctrl+Up / Ctrl+Down (field chip) | field panel + chooser | Moves the field to the end of the previous / next area in panel order (Filters, Rows, Columns, Values). |
| Delete (field chip) | field panel + chooser | Removes the field from the layout. In the chooser’s onDemand mode every move edits the draft until Apply. |
| Up / Down / Home / End / Escape / Tab (menu) | menu | APG menu keys over the enabled items; Escape and Tab close it and return focus to the chip or header that opened it (a moved chip is re-focused in its new area). |
OgeBpmnEditor — Canvas keyboard
@oge-ui/bpmn
| Key or item | Scope | Behaviour |
|---|---|---|
| role="application" canvas | Tab / Shift+Tab · arrows (Shift = 1px) · C · A · H / L / S · F2 / Enter · Delete · Ctrl+Z / Ctrl+Y · Ctrl+C / Ctrl+X / Ctrl+V · Ctrl+A · Ctrl+F · + / − / F · Escape | Tab cycles elements (never trapped on an empty selection — leave with Escape then Tab, announced in the canvas hint), arrows move the selection by one grid step, C arms the connect tool (Tab/arrows walk candidate targets, Enter commits), A appends a connected task, H / L / S switch to the hand / lasso / space tool (edit mode only), F zooms to fit, F2 /Enter edit the label, Ctrl+C/X/V copy/cut/paste via the internal clipboard, Ctrl+A selects all, Ctrl+F opens the element search overlay, Escape cancels the active tool or drag. The selected element is exposed via aria-activedescendant and every action is narrated in a polite live region. |
Grid and tree list keyboard
The grid is an APG grid (a treegrid when it groups or shows detail rows); the tree list is a treegrid. Every pointer gesture has a keyboard alternative (WCAG 2.1.1 and 2.5.7):
| Keys | Where | Does |
|---|---|---|
Alt + ← / → | Column header | Resize the column (the resize handle is a separator ) |
Ctrl + Shift + ← / → | Column header | Move the column, announced |
Ctrl + ↑ / ↓ | Row (row drag on) | Move the row |
Ctrl + ↑ / ↓ | Column chooser | Reorder the list |
| Keyboard on the chips | Group panel | Group, ungroup and reorder groups |
Ctrl + → / ← (tree list) | Row (row drag on) | Indent / outdent under a sibling |
Screen readers
- One announcer per document. Families announce through a shared pair of visually hidden live regions (
[data-oge-live-announcer="polite"]and"assertive"), so two grids on a page never talk over each other. Messages are debounced (100 ms), de-duplicated within a second and cleared after five. - What the grid and tree list announce: sort changes, the row count after filtering or searching, page changes, group and row expansion, selection counts, range selection, paste / fill, undo / redo and validation errors (assertive). Turn them off per instance or app-wide with
announcements; translate them with the message catalog. - Errors are tied to their field: an invalid cell or form field sets
aria-invalid,aria-errormessageandaria-describedby. - Charts, the pivot grid, kanban, pagination, the carousel and badges keep their own polite regions for changes that only they can describe.
- Not yet done: there is no recorded manual test with a screen reader (NVDA, JAWS, VoiceOver, TalkBack). Everything on this page is checked by automated tests of the ARIA output; a report from a screen-reader user is a bug like any other.
Forced colors, motion and direction
| Preference | What the components do | Checked by |
|---|---|---|
| Forced colors (Windows High Contrast) | System colours only; the focus ring is an outline that survives; selection paints Highlight ; on/off states are not colour alone | forced-colors.spec.ts |
| Reduced motion | CSS transitions drop to zero; scripted motion asks prefersReducedMotion() first | reduced-motion.spec.ts |
| Right-to-left | Logical CSS properties; arrow keys mirror; charts, Gantt and the BPMN chrome flip (the BPMN canvas stays left-to-right) | rtl.spec.ts |
| Contrast | Default, dark and high-contrast themes hold text and controls to WCAG AA | contrast.spec.ts , themes.spec.ts , high-contrast.spec.ts |
| Target size | Small controls get a 24 px hit area, 44 px on coarse pointers | Stylesheet mixin ( hit-area ); no dedicated spec |
Automated checks
| Check | Runs | Covers |
|---|---|---|
| axe crawl | Nightly | Every sitemap route in both layers, wcag2a , wcag2aa , wcag21aa , wcag22aa , plus colour contrast on every component |
| Component axe specs | Every pull request | About 95 spec files scan the components they drive, in both layers |
| Contrast | Every pull request | A dozen representative pages, light and dark, components only |
| Announcements and errors | Every pull request | grid-announcements.spec.ts — live region text, aria-sort , error wiring |
| Forced colors, reduced motion, RTL | Every pull request | Emulated media and dir="rtl" ; computed styles and key handling |
Two axe rules are switched off in the per-component specs, with the reason in the spec: heading-order (the docs pages put demo headings under the page title by design) and, for leading utility columns that carry an aria-label but no visible text, empty-table-header — a best-practice rule, not a WCAG criterion. color-contrast is scanned separately, on the components only, so a demo's own colours cannot hide a component failure.