Accessibility

Keyboard support, ARIA, and reduced motion.

A picker is an input, so it behaves like one. All of this is on by default and none of it needs configuring.

Keyboard

Focus the track and it answers:

KeyDoes
step one item (horizontal track)
step one item (vertical track)
PgUp PgDnjump five
Home Endfirst and last item
Enter Spacechoose the centered item

The arrows follow the axis, so an arrow key always moves the track the way it points.

Screen readers

The container is a listbox, each slot an option, and a single id hops to whichever slot is centered so aria-activedescendant can stay put on the container.

html
<div class="loopem loopem-interactive" role="listbox"
     tabindex="0" aria-orientation="horizontal"
     aria-activedescendant="loopem-active-1">
  <div class="loopem-track">
    <div class="loopem-slot" role="option" data-loopem-key="3" aria-selected="false">…</div>
    <div class="loopem-slot" role="option" data-loopem-key="4" id="loopem-active-1"
         data-loopem-centered aria-selected="true">…</div>
  </div>
</div>

If you put your own focusable element inside a slot, it stays focusable and reachable in the normal way. The track owns the container’s focus, not yours.

Reduced motion

Under prefers-reduced-motion, autoplay never starts. Motion that begins with no way to have asked for it is precisely what that setting refuses.

Dragging, flicking and the settle spring still work, because those are motion someone asked for by touching the thing.

Touch and pointer

The track claims one axis only. A horizontal one keeps touch-action: pan-y, so a thumb dragged up the page over it still scrolls the page. A diagonal swipe is decided by its first few pixels and handed to whichever of the two it more nearly belongs to. Nobody gets trapped.

What you still have to do

Labelling. Loopem does not know what your items are, so give each one an accessible name and give the container one too:

ts
createPicker(el, {
  items: colors,
  renderItem: (color) => {
    const button = document.createElement('button')
    button.type = 'button'
    button.setAttribute('aria-label', color.name)
    return button
  },
})
html
<div id="picker" aria-label="Colorway"></div>