Accessibility
What Flexiboards does for keyboard and screen-reader users, and what your markup needs to add.
What the library provides
Flexiboards renders semantic roles and live announcements without any configuration:
- The board is a
role="application"region, described by a hidden instructions element and markedaria-busywhile a layout is pending. - Each target’s grid is
role="grid"witharia-colcountandaria-rowcount. - Each placed widget is a
role="gridcell"owned by arole="row". Row and column indices start at 1; spans describe the widget’s size. Controller coordinates and stored layouts still start at 0. Rows usearia-ownsso moving a widget does not remount its content within a target. - A held widget temporarily becomes a
role="group"without grid coordinates. Its decorative preview is hidden from assistive technology and cannot receive focus. Empty targets expose an “Empty drop target” cell. data-flexi-widgetidentifies rendered widgets in every interaction state. The legacyaria-grabbedandaria-dropeffectattributes remain for compatibility; live announcements communicate the actions.- A visually hidden
aria-liveannouncer inside the board reports grabs, resizes, releases, and rejected drops.
Keyboard
A widget that can be grabbed is in the tab order. If it contains a FlexiGrab, the handle takes its place in the tab order instead, and FlexiResize handles are buttons in the tab order when resizing is enabled. A disabled resize handle is skipped.
| Key | On | Effect |
|---|---|---|
| Tab | Page | Moves focus between widgets, grab handles, resize handles, and adders. |
| Enter | Focused widget or grab handle | Grabs the widget from its centre. |
| Enter | Focused resize handle | Starts resizing the widget. |
| Enter | Focused adder | Creates the adder’s widget and grabs it. |
| ← → ↑ ↓ | While grabbed or resizing | Moves the widget, or its resize edge, by a small step. Hold Shift for a large step, or Ctrl / Cmd for a fine one. |
| Enter | Anywhere, while grabbed or resizing | Drops the widget where it currently is. |
| Escape | Anywhere, while grabbed or resizing | Cancels and returns the widget to where it started. |
A keyboard grab drives the same virtual pointer as a mouse drag, so the widget follows the arrow keys across cells and between targets exactly as it would follow a cursor. Tab is trapped while a widget is held, so focus cannot leave until you drop or cancel.
What you need to add
- Label handles and adders.
FlexiGrab,FlexiResize,FlexiAdd, andFlexiDeleterender their own elements but not their own text. Put a visually hiddenspaninside icon-only content. - Make state visible. The
isGrabbed,isShadow,isResizing, anddropRejectedflags on the widget controller are yours to style; the library only announces them. See Widget Rendering. - Respect reduced motion. Flexiboards transitions move and resize widgets, which is the kind of motion
prefers-reduced-motionasks you to remove. When it is set, leavetransitionout of the configuration so widgets snap into place. Opacity and colour changes in your own widget styling can stay; the preference is about movement, not every animation. - Keep custom content operable. Buttons and links inside a widget keep working while the widget is draggable, but on touch devices a full-widget drag competes with scrolling. Prefer a grab handle, or the
longPressTriggerConfig()grab trigger, where widgets contain interactive content.
Verify accessibility
Run keyboard checks against your own widget content: grab, move, resize, drop, cancel, and Tab out after the action. Check that focus stays on the active control, that disabled handles are skipped, and that activating a nested button does not grab its widget.
This repository runs adapter unit tests, axe-core checks in Playwright, and browser accessibility-tree assertions. The browser suite exercises both frameworks, including cross-target keyboard drops. Run it with pnpm -C site e2e accessibility.spec.ts after building the packages.
Automated checks cover markup and interaction regressions. Test your application with a screen reader too, particularly nested boards, custom controls, and the wording of announcements. Follow the WAI-ARIA grid and table guidance when inspecting positions and spans.