Vize

Grid List

Accessible, unstyled GridList (WAI-ARIA APG grid pattern for interactive lists): roving focus, typeahead, single/multiple selection with ranges, list or 2D grid layouts, and pointer + keyboard drag reordering.

Package @vizejs/ui/grid-list
Maturity stable
Own the source vize lib pull grid-list
Requires collection, context, controllable-state, drag-and-drop, id, sortable, typeahead
Aliases selectable list, reorderable list, card grid, gallery grid
Covers WAI-ARIA grid pattern, React Aria GridList, Reka UI Listbox

Usage

import { GridList, GridListItem } from "@vizejs/ui/grid-list";

Or copy the source into your project with vize lib pull grid-list (see Source Distribution).

API

GridList<Item>

Source: src/families/data/grid-list/grid-list.vue

Props

Prop Type Default Description
items (required) readonly Item[] undefined Items rendered as rows.
getKey (item: Item, index: number) => string undefined Stable key per item; defaults to the index.
getTextValue (item: Item) => string undefined Typeahead text per item; defaults to the rendered text.
id string | null undefined Consumer-owned list id. null and undefined select a deterministic fallback.
selectionMode GridListSelectionMode "single" Selection policy.
selection readonly string[] undefined Controlled selected keys (v-model:selection).
defaultSelection readonly string[] [] Initial uncontrolled selection.
disabledKeys readonly string[] [] Keys that stay focusable but cannot be selected, activated, or dragged.
layout GridListLayout "list" list moves with Up/Down; grid also moves with Left/Right and steps Up/Down by columns.
columns number 1 Items per visual row in the grid layout.
dir "ltr" | "rtl" "ltr" Reading direction for Left/Right in the grid layout.
loop boolean false Wrap arrow navigation at both ends.
reorderable boolean false Allow pointer and keyboard reordering through the slot's dragHandleProps.
ariaLabel string undefined Accessible name of the grid.
ariaLabelledby string undefined Ids that label the grid.

Events

Event Payload Description
update:selection [value: readonly string[]] Fired with the new selected keys (supports v-model:selection).
action [item: Item, key: string] Fired when Enter or a double click activates an enabled item.
update:items [value: readonly Item[]] Fired with the reordered items (supports v-model:items).
reorder [event: GridListReorderEvent<Item>] Fired after a reorder commits.

Slots

Slot Slot props Description
item GridListItemSlotProps<Item> Item contents.
empty — Rendered when items is empty.

Exposed

Member Type Description
element HTMLDivElement | null Rendered role="grid" element.
focus (key?: string) => void Focus an item by key (or the active/first item).
selectAll () => boolean Select every enabled item (multiple selection only).
clearSelection () => boolean Clear the selection.

GridListItem

Source: src/families/data/grid-list/grid-list-item.vue

Props

Prop Type Default Description
itemKey (required) string undefined Stable item key (registry key and DOM data hook).
index (required) number undefined Zero-based item index, published as aria-rowindex (one-based).
selected boolean false Whether the item is selected.
disabled boolean false Whether the item is disabled (focusable, not selectable or draggable).
textValue string undefined Typeahead text; rendered text is used when omitted.

Slots

Slot Slot props Description
default { readonly active: boolean; readonly dragging: boolean; readonly dragHandleProps: Readonly<DragSourceProps> | null; } Item contents. Receives drag state and handle props.

Behavior

@vizejs/ui/grid-list applies the WAI-ARIA APG grid pattern to interactive lists. grid-list.vue is the generic root (Item); grid-list-item.vue renders each role="row" with one role="gridcell". Reordering uses the shared sortable foundation through a drag handle. Every row is proven by the named test in grid-list.test.ts or grid-list-ssr.test.ts.

# State Input Outcome Proven by
L1 any render role="grid" with aria-rowcount, rows with aria-rowindex and one gridcell, a single tab stop renders an APG grid of rows with one gridcell and a single tab stop
L2 layout="list" Up/Down, Home/End, PageUp/PageDown, loop, characters roving focus moves, wraps with loop, and typeahead matches getTextValue list layout: Up/Down, Home/End, PageUp/PageDown, loop, and typeahead
L3 layout="grid" Left/Right, Up/Down, dir="rtl" Left/Right step items, Up/Down step by columns, rtl flips grid layout: Left/Right step items, Up/Down step rows, rtl flips
L4 selectionMode="multiple" click, Ctrl, Shift, Space, Shift+Arrow, Ctrl+A replace, toggle, and range selection skipping disabled items; aria-selected / aria-disabled multiple selection: click, Ctrl-click, Shift-click, Space, Shift+Arrow, Ctrl+A
L5 single / none click, Enter, double click single replaces; none publishes no aria-selected; Enter and double click emit action single selection replaces; none mode publishes no aria-selected; Enter and double click act
L6 reorderable Enter on handle, arrows, Enter a keyboard move commits; reorder and update:items fire; list keys ignore handle events keyboard reorder through the drag handle commits and emits the new order
L7 no items render an empty row renders the empty slot empty lists render an empty row
L8 custom compositions import GridListItem is exported GridListItem is exported for custom compositions
L9 SSR two requests + hydrate byte-identical markup with one tab stop; warning-free hydration renders identical grid-list markup across SSR requests and hydrates cleanly