Dashral Pro is hereSee pricing

Dashral

SortableNew

Items you put in order by dragging: a menu, priorities, a table's columns, a product's photos.

$ pnpm dlx shadcn@latest add @dashral/sortable
  • Overview
  • Orders
  • Products
  • Customers
  • Reports
  • Messages

Sidebar: Overview · Orders · Products · Customers · Messages

Installation

$ pnpm dlx shadcn@latest add @dashral/sortable

Adds the component, the components it builds on, its npm packages and the theme tokens it uses. Or by its full URL: https://dashral.com/r/sortable.json

When to use

  • Putting things in order by dragging: menu items, a playlist, priorities; keyboard works too.

When not to use

  • Sorting by a column: Data Table.
  • Moving cards between columns: a board.

Usage

Save the new order in onReorder.

example.tsx
"use client"

import { Sortable } from "@/components/dashral/sortable"

const pages = [
  { id: "home", title: "Home" },
  { id: "pricing", title: "Pricing" },
  { id: "blog", title: "Blog" },
]

export default function MenuOrder() {
  return (
    <Sortable
      variant="card"
      aria-label="Menu order"
      items={pages}
      onReorder={(items) => console.log("save order", items.map((item) => item.id))}
    />
  )
}

Using the npm package? Import from @dashral/ui/components/sortable instead, here and in the examples; the rest is the same.

Examples

Priorities

numbered and dragBy="item": the whole row moves and the numbers count along.

  • Export reports to PDF48 requests
    Reports
  • Sign in with SSO41 requests
    Security
  • Bulk edit products33 requests
    Catalog
  • Dark mode for invoices21 requests
    Billing
  • Retry failed webhooks17 requests
    Developers

Table columns

size="sm", a Checkbox per column, and the first column disabled: it stays first, and nothing can be dropped above it.

  • Invoice
  • Customer
  • Status
  • Amount
  • Due date
  • Owner
InvoiceCustomerStatusAmount

Featured products

layout="grid": tiles move anywhere; the first leads the storefront, and removing one closes the gap.

  • Film camera$189
    Featured first
  • Smartphone$699
  • Game controller$59
  • Reading glasses$45
  • Laptop$1,299

API reference

Sortable

Also takes every prop of <ul>(opens in a new tab).

PropTypeDefault
items{ id, title, description?, media?, meta?, actions?, label?, disabled? }[]

The items, in order. Each id is unique and stays the same. Required.

—
onReorder(items, { id, from, to }) => void

The new order after each drop, and the move that made it. Without it the list keeps its order itself.

—
layout"list" | "grid"

Rows that move up and down, or tiles that move anywhere.

"list"
dragBy"handle" | "item"

Pick up by a grip at the start, or by the whole item. Its own buttons and fields never start a drag.

"handle" in a list, "item" in a grid
numberedboolean

Its position before each item, counting along while you drag.

false
variant"default" | "card"

A list's rows on the page, or inside a bordered card.

"default"
dividedboolean

Lines between a list's rows.

true
size"sm" | "default"

sm for popovers, sidebars and dense panels.

"default"
disabledboolean

Nothing can move. An item's own disabled keeps that one in place: it can't be picked up, and nothing is dropped past it.

false
emptyReactNode

Shown in place of the items when there are none.

—
classNames{ item, handle, media, title, description, meta, actions }

Classes for each part.

—
classNamestring

Extra classes, merged with cn() so yours win.

—

Keyboard

KeysAction
TabTo each grip (or item), then its own controls
SpaceorEnterPick up the focused item, or drop it
Arrow keysMove the item you hold
EscapePut it back where it was

Accessibility

  • A <ul role="list">. Each grip (or item, with dragBy="item") is a button announced as a sortable item, described by how to move it from the keyboard.
  • Picking up, each move and the drop are announced with the item's name and its position ("position 2 of 5"), in the kit's words; give label when title isn't text.
  • A touch on an item waits for a press and hold, so swiping still scrolls the page; a grip starts at once.

Motion

  • The others slide out of the way (--duration-standard, --ease-standard), and the item you hold rises with a shadow. With reduced motion they move without sliding.