Skip to content
LyEve UI v0.60.1

Layout & display

SortableList

A list a person puts in order. A row moves when its handle is dragged, from the handle's menu, or with Alt and an arrow key, and every move is announced in the row's own words.

Basic

Bind items and a move writes the new order back. Each item carries an id and a label. The rows are keyed by the id, so it has to be stable and unique in the list, and a repeated id throws in development. The label names the row's handle and every sentence a move announces. The row snippet draws what sits beside the handle, and it receives the item and its index.

  • 1. Hero Image and heading
  • 2. Features Three columns
  • 3. Pricing Plan table
  • 4. FAQ Questions
  • 5. Footer Links

Press Alt with the up or down arrow to move a row, or Enter for a menu.

Order: hero, features, pricing, faq, footer

From the keyboard

Tab reaches each row's handle. Alt with the up or down arrow moves the row that holds the focus, and the focus stays on its handle, so the next press moves the row again. Alt is Option on a Mac. Enter, Space or an arrow alone opens the handle's menu, whose Move up and Move down make the same moves. During a drag, Escape puts the row back where it started.

The keys work from anywhere in the row, so a row that draws its own controls needs no extra tab stop. Alt with an arrow pressed in a text field stays with the field, where Option and an arrow move the caret on macOS. A control in the row that handles the key itself and calls preventDefault keeps it too.

With a pointer

A mouse lifts a row once it moves a few pixels with the button down. A finger lifts it after resting a quarter of a second on the handle, so a swipe that starts on a handle still scrolls the page. The lifted row follows the pointer, a line marks where it will land, and the box that scrolls the list scrolls when the pointer nears its edge. Escape or a second finger puts the row back.

A click or a tap on the handle that lifts nothing opens the menu. That is the way in for a pointer that cannot drag and for a screen reader on a phone. A drag follows its row by id, so a list that changes during a drag still moves the row that was lifted, and removing that row ends the drag.

What a screen reader hears

The list is named by label. Each handle reads "Move" and the row's label, and its description names the keys. Every move, and every move that cannot happen, is said in a polite live region: "Hero moved to position 2 of 5.", "Hero is already first.", or the sentence canMove returned.

Refusing a move and saving the order

canMove is asked before every move, whether it comes from a drag, a key or the menu. It returns true to allow the move, or the sentence to announce in its place. While a lifted row is over a refused place, the line turns to the danger tone and a drop there puts the row back. onmove is called once a move has landed, with the row, the index it left, the index it reached and the whole list in its new order, which items already holds. It is the place to save the order.

  • Hero
  • Features
  • Pricing
  • FAQ
  • Footer

Press Alt with the up or down arrow to move a row, or Enter for a menu.

No move yet. Try to move a row below the footer.

API

PropTypeDefaultDescription
items requiredT[] no defaultThe rows, in order. Bindable, and a move writes the new order back.
label requiredstring no defaultNames the list for a screen reader.
row requiredSnippet<[T, number]> no defaultDraws a row's content beside its handle, from the item and its index.
canMove (item: T, from: number, to: number) => true | string no defaultAllows a move with true, or refuses it with the sentence to announce instead.
onmove (move: SortableMove<T>) => void no defaultCalled once a move has landed, when items already holds the new order.
class string no defaultExtra classes on the wrapper.

SortableItem

T is any type that extends SortableItem, so an item can carry whatever the row draws.

PropTypeDefaultDescription
id requiredstring no defaultStable, and unique in the list. A changed id remounts its row.
label requiredstring no defaultThe row's name: its handle reads "Move" and the label, and moves announce it.

SortableMove

PropTypeDefaultDescription
item requiredT no defaultThe row that moved.
from requirednumber no defaultThe index it left.
to requirednumber no defaultThe index it reached.
items requiredT[] no defaultThe list in its new order, which items holds as well.