GridList
An interactive row list built from plain, already-ordered markup.
View code
let model = new SelectionModel({ keys: THREADS.map((thread) => thread.id) });
// ref() fires on insert, so the subscription is set up in the browser and torn
// down with the node — the server renders the list without one.
let followSelection = ref((_node, signal) => {
model.addEventListener("change", () => void handle.update(), { signal });
});
<div mix={[followSelection]}>
<div mix={[hstack({ gap: 2, align: "center" })]}>
<Button variant="outline" color="neutral" size="sm" disabled={model.isEmpty}>
<ArchiveIcon />
Archive
</Button>
<Button variant="outline" color="danger" size="sm" disabled={model.isEmpty}>
<Trash2Icon />
Delete
</Button>
<Badge color="neutral">{model.size} selected</Badge>
</div>
<GridList aria-label="Inbox" mix={[gridListKeys(model)]}>
{SECTIONS.map((section) => (
<GridList.Section key={section} aria-labelledby={`inbox-${section}`}>
<GridList.Header id={`inbox-${section}`}>{section}</GridList.Header>
{THREADS.filter((thread) => thread.section === section).map((thread) => (
<GridList.Item key={thread.id} id={thread.id}>
<MailIcon aria-hidden="true" />
<span mix={[is("7rem"), shrink(), truncate()]}>{thread.from}</span>
<span mix={[basis(0), grow(), truncate()]}>{thread.subject}</span>
<span mix={[basis(0), grow(), truncate()]}>{thread.preview}</span>
</GridList.Item>
))}
</GridList.Section>
))}
</GridList>
</div>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/uiimport "@sdxc/ui/theme.css";Usage
import { GridList } from "@sdxc/ui";Renders the list's root host as a bordered <div> with role="grid",
keeping its row-list layer in an inner wrapper since a @container query
can't resolve against the host that declares it; reach parts.list to adjust it.
Composition
The parts the component publishes, each a static property of the host.
GridListGridList.ItemRenders a single row: a<div>carryingrole="row", itsidmirrored onto adata-rmx-keyattribute so a paired selection, keyboard-navigation, or reorder behavior can correlate the row with its own state.GridList.SectionRenders a titled group of rows: a<div>carryingrole="rowgroup", stacking an optional GridList.Header above its GridList.Item rows, with a block-start rule before every section but the first.GridList.HeaderRenders a section's label: a<header>styled as small, muted, uppercase text for the GridList.Item rows nested beneath it in a GridList.Section; point the section'saria-labelledbyat itsid.GridList.DragHandleRenders the drag-grab element of a row: a native<button type="button">written before the consumer's own attributes, so acommand/commandforpair still runs inside a<form>— atypeseen only after them is ignored.
Examples
<GridList aria-label={t("gallery.title")} layout="grid">
<GridList.Item id="photo-1">{t("gallery.photo", { name: "Sunset" })}</GridList.Item>
<GridList.Item id="photo-2">{t("gallery.photo", { name: "Harbor" })}</GridList.Item>
</GridList>Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
| Prop | Type | Description |
|---|---|---|
layout? | "stack" | "grid" | Row arrangement. Defaults to DEFAULT_LAYOUT. |
children | RemixNode | GridList.Item, GridList.Section, and GridList.LoadMoreItem rows to render. |
parts? | PartsProps | Per-part styling for the list's internal row-list wrapper. |
Also accepts everything in TagProps<"div">.
GridList.Item
| Prop | Type | Description |
|---|---|---|
id | string | Stable identifier for this row, mirrored onto both the rendered element's own id and a data-rmx-key attribute, so the row is already correlation-ready for a paired behavior once one is attached. |
Also accepts everything in TagProps<"div">.
GridList.Section
| Prop | Type | Description |
|---|---|---|
children | RemixNode | The section's optional GridList.Header label, followed by its GridList.Item rows. |
Also accepts everything in TagProps<"div">.
GridList.Header
Also accepts everything in TagProps<"header">.
GridList.DragHandle
| Prop | Type | Description |
|---|---|---|
"aria-label" | string | Accessible name for the icon-only control, e.g. "Reorder" or "Drag to reorder". |
Also accepts everything in Omit<TagProps<"button">, "type" | "children">.
Types
| Name | Values | What it decides |
|---|---|---|
Layout | "stack" | "grid" | Arrangement of GridList.Item rows: "stack" renders them as a single column, "grid" wraps them into a multi-column layout growing from two columns up to four as the list's own container widens. |