Sortable List
SortableList — a drag-to-reorder list over dnd-kit.
Real use · reorder a page's sections (drag the handle)
- Hero banner
- Feature grid
- Pricing table
- Testimonials
- FAQ
Using Sortable List
Silica ships one design system through three paths. They share a class vocabulary but are not interchangeable — pick the one that matches what you are building.
Plain HTML — CSS classes
The Tailwind v4 plugin. Works in any framework or none — Rails, Django, PHP, Go, a static file. This path ships no JavaScript, so a component that needs interaction is styled but inert.
/* in your CSS */
@import "tailwindcss";
@plugin "@wizeworks/silicaui";Root class sortable-handle, with 2 modifiers:
.sortable-handle.sortable-item.sortable-list
React
Typed components over those same classes, with behavior and accessibility from Base UI.
npm i @wizeworks/silicaui-dndimport { SortableList } from "@wizeworks/silicaui-dnd";Props
| Prop | Type | Required | Description |
|---|---|---|---|
| items | T[] | yes | The ordered items. |
| getItemId | (item: T) => string | number | yes | Stable id for each item (drag identity + React key). |
| getItemLabel | (item: T) => string | no | What to CALL an item out loud. |
| onReorder | (items: T[]) => void | yes | Called with the reordered array after a drag or keyboard move. |
| renderItem | (item: T, ctx: SortableItemContext) => React.ReactNode | yes | Render a row's CONTENTS. |
| handle | boolean | no | Drag only via a handle element you render with ctx.handleProps (rather than the whole row). Default false (the whole row is draggable). |
| className | string | no | Added to the <ul>. |
| itemClassName | string | no | Added to every row <li>, alongside the row's own class. |
Source of the demo above
The exact file that renders the examples above, so it can never drift from them. It imports a few of this site’s own layout helpers (../lib/…), so read it for the component calls rather than copying it whole.
Show source
import { useState } from "react";
import { SortableList } from "@wizeworks/silicaui-dnd";
import { useSilicaClass } from "@wizeworks/silicaui-react";
import { Section } from "../lib/Section";
interface SectionBlock {
id: string;
label: string;
}
const INITIAL: SectionBlock[] = [
{ id: "hero", label: "Hero banner" },
{ id: "features", label: "Feature grid" },
{ id: "pricing", label: "Pricing table" },
{ id: "testimonials", label: "Testimonials" },
{ id: "faq", label: "FAQ" },
];
const GripIcon = (
<svg viewBox="0 0 24 24" fill="currentColor" stroke="none">
<circle cx="9" cy="6" r="1.6" />
<circle cx="15" cy="6" r="1.6" />
<circle cx="9" cy="12" r="1.6" />
<circle cx="15" cy="12" r="1.6" />
<circle cx="9" cy="18" r="1.6" />
<circle cx="15" cy="18" r="1.6" />
</svg>
);
export function SortableListDemo() {
const [blocks, setBlocks] = useState<SectionBlock[]>(INITIAL);
const sc = useSilicaClass();
return (
<Section title="Real use · reorder a page's sections (drag the handle)">
<div className="max-w-sm">
<SortableList
items={blocks}
getItemId={(b) => b.id}
onReorder={setBlocks}
handle
renderItem={(block, ctx) => (
<>
<span
{...ctx.handleProps}
className={sc("sortable-handle") as string}
aria-label={`Drag ${block.label}`}
>
{GripIcon}
</span>
{block.label}
</>
)}
/>
</div>
</Section>
);
}The full API for Sortable List, on every path, is available through the Silica MCP server.