Sortable
Overview
Section titled “Overview”Sortable owns an ordered List<string> of stable keys and re-renders into the new
order on every reorder; the consumer iterates the same list to render one Item per key.
Pointer drag visuals are painted by the engine straight onto the DOM, so they never
fight a C# re-render, while a keyboard reducer (grab, move live, drop, cancel)
implements the WAI-ARIA APG grab-and-move model and announces each transition through a
visually-hidden live region. It can be controlled (@bind-Values) or uncontrolled
(DefaultValues), and fires OnReorder with the old and new index on every committed
reorder.
Anatomy
Section titled “Anatomy”@using Navius.Primitives.Components.Sortable
<NaviusSortable> <NaviusSortableItem> <NaviusSortableItemHandle /> </NaviusSortableItem></NaviusSortable>Owns the key order, the keyboard grab/roving state and the drag engine. Renders a
div with role="list" plus a visually-hidden live region. Values is two-way
bindable.
| Prop | Type | Default | Description |
|---|---|---|---|
Values |
IReadOnlyList<string>? |
- | The ordered item keys. Pair with ValuesChanged (@bind-Values); the consumer iterates this list to render items. |
ValuesChanged |
EventCallback<IReadOnlyList<string>> |
- | Fires when the controlled Values should change. |
DefaultValues |
IReadOnlyList<string>? |
- | Uncontrolled initial order, seeding the internal list when Values is not supplied. |
Orientation |
SortableOrientation |
Vertical |
The reorder axis (Vertical, Horizontal, or Grid), driving the engine’s midpoint math. |
Disabled |
bool |
false |
Disables the whole list. |
OnReorder |
EventCallback<SortableReorderEventArgs> |
- | Fires once per committed reorder with the old and new index (OldIndex, NewIndex), from both pointer and keyboard moves. |
ChildContent |
RenderFragment? |
- | The sortable’s items. |
Attributes |
IDictionary<string, object>? |
- | Forwarded to the rendered div. |
One reorderable row: the drag target and the roving keyboard focus target. Value is
the stable key. Renders a div with role="listitem".
| Prop | Type | Default | Description |
|---|---|---|---|
Value |
string |
- (required) | The stable key that identifies this item in the sortable’s order. |
Label |
string? |
Value |
Accessible name used in live-region announcements. |
Disabled |
bool |
false |
Disables this row; skipped by roving keyboard navigation. |
ChildContent |
RenderFragment? |
- | Row content. |
Attributes |
IDictionary<string, object>? |
- | Forwarded to the rendered div. |
ItemHandle
Section titled “ItemHandle”An optional drag grip; its presence scopes pointer drag to the handle. aria-hidden
since keyboard reordering acts on the whole item, not the handle. Renders a span.
| Prop | Type | Default | Description |
|---|---|---|---|
ChildContent |
RenderFragment? |
- | Handle content (e.g. a grip glyph). |
Attributes |
IDictionary<string, object>? |
- | Forwarded to the rendered span. |
Data attributes
Section titled “Data attributes”| Part | Attribute | Description |
|---|---|---|
| Root | data-orientation |
"vertical" | "horizontal" | "grid". |
| Root | data-disabled |
Present when disabled. |
| Root | data-dragging |
Present while a drag or keyboard grab is active anywhere in the list. |
| Item | data-dragging |
Painted by the engine on the item currently being dragged. |
| Item | data-drop-target |
Painted by the engine on the hovered drop slot. |
| Item | data-keyboard-grabbed |
Present while this item is grabbed for keyboard reordering. |
| Item | data-disabled |
Present when the row or the whole list is disabled. |
Keyboard interactions
Section titled “Keyboard interactions”| Key | Behavior |
|---|---|
Space / Enter |
Grabs the focused item, or drops a grabbed item at its new position. |
| Arrow keys | While grabbed, moves the item live; otherwise moves the roving focus. |
Home / End |
Moves the item (or focus) to the first / last position. |
Escape |
Cancels a grab and restores the original order. |
ARIA mechanism
Section titled “ARIA mechanism”Follows the APG grab-and-move pattern. The Root carries aria-disabled when
Disabled. Each Item is a roving tab stop with aria-roledescription="sortable item";
grabbing sets aria-grabbed="true" and data-keyboard-grabbed. Every grab, move, drop
and cancel is announced through a role="status" polite live region. Cross-list
transfer is not supported: the engine reports indices relative to a single container
only. This mechanism is covered by the Playwright browser test suite and gated by
axe-core in CI.