0.4.1

Overview

Keyboard navigation, focus management, and screen reader support built into the widget.

Scena is accessible out of the box: every interactive element is keyboard-operable, exposes ARIA roles and attributes, and keeps a visible focus indicator. No extra configuration is required.

Keyboard navigation

ElementKeysAction
Video container (preview)Enter / SpaceExpand the widget
Progress barArrowLeft / ArrowDownSeek backward
Progress barArrowRight / ArrowUpSeek forward
Progress barHome / EndJump to start / end
Control buttonsEnter / SpaceActivate (play, pause, mute, close, CTA)

The seek step is a fraction of the video duration, 0.05 (5%) by default. Configure it via the step prop of the progress component:

const scena = useScena({
  config: {
    videoProgress: {
      step: 0.1 // seek 10% per keypress
    }
  }
});

Video controls and volume buttons appear on :focus-within as well as on hover, so keyboard users always see which control is focused.

Focus management

In preview mode the collapsed widget acts as a single button: the container is the only tab stop and its inner controls are skipped, so keyboard users don't tab through invisible elements.

When the widget expands, focus moves to the first available control — progress bar, then play/pause, then volume — depending on which components are enabled. When it collapses while focus is inside, focus returns to the container instead of being lost to the page.

Screen readers

The container exposes role="button", and the progress bar exposes role="slider" with aria-valuemin, aria-valuemax, and aria-valuenow. The current position is announced as human-readable time via aria-valuetext — for example 1:25 / 3:40 — instead of raw percentages.

Every interactive component accepts an aria prop to override or extend its attributes:

const scena = useScena({
  config: {
    videoContainer: {
      aria: {
        ariaLabel: 'Watch product demo'
      }
    },
    videoControls: {
      aria: {
        play: { ariaLabel: 'Play demo video' },
        pause: { ariaLabel: 'Pause demo video' }
      }
    }
  }
});

The available attributes are defined by ComponentAriaProps:

interface ComponentAriaProps {
  ariaLabel?: string;
  ariaLabelledby?: string;
  ariaDescribedby?: string;
  ariaDisabled?: boolean;
  ariaExpanded?: boolean;
  ariaControls?: string;
  ariaPressed?: ComponentAriaPressed;
  ariaHaspopup?: ComponentAriaHaspopup;
}

See the component pages for the aria shape each component accepts — videoControls and videoVolume take per-button overrides.