v1.0
Introduction / Page 01·04

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 marked aria-busy while a layout is pending.
  • Each target’s grid is role="grid" with aria-colcount and aria-rowcount.
  • Each placed widget is a role="gridcell" owned by a role="row". Row and column indices start at 1; spans describe the widget’s size. Controller coordinates and stored layouts still start at 0. Rows use aria-owns so 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-widget identifies rendered widgets in every interaction state. The legacy aria-grabbed and aria-dropeffect attributes remain for compatibility; live announcements communicate the actions.
  • A visually hidden aria-live announcer 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.

KeyOnEffect
TabPageMoves focus between widgets, grab handles, resize handles, and adders.
EnterFocused widget or grab handleGrabs the widget from its centre.
EnterFocused resize handleStarts resizing the widget.
EnterFocused adderCreates the adder’s widget and grabs it.
While grabbed or resizingMoves the widget, or its resize edge, by a small step. Hold Shift for a large step, or Ctrl / Cmd for a fine one.
EnterAnywhere, while grabbed or resizingDrops the widget where it currently is.
EscapeAnywhere, while grabbed or resizingCancels 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, and FlexiDelete render their own elements but not their own text. Put a visually hidden span inside icon-only content.
  • Make state visible. The isGrabbed, isShadow, isResizing, and dropRejected flags 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-motion asks you to remove. When it is set, leave transition out 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.