shadcn.io is not affiliated with official shadcn/ui
Sort Options Dialog Block for React
A data-grid tool's sort dialog shown open: up to three rules with a field and a direction each, Move up, Move down and Remove, a sorted five-row preview with the sorted columns numbered, and the table re-sorting on apply.
Installation
Overview
Let people say how a table is ordered, and what breaks a tie, with this sort dialog for React with Base UI. It opens from the Tasks page of Sortleaf, a data-grid tool: the page's header holds an outline Sort Button, and the table, a toolbar with a Sort chip, a head of bars and six ruled rows with real titles and dates, is drawn under a soft scrim inside a hairline frame with a plus mark on each corner. The Dialog lists up to three rules, each a Native Select for the field, Due date, Priority, Assignee or Title, a Segment Group for the direction with an arrow and a word, and Move up, Move down and Remove buttons. A five-row preview under them is sorted by the same stable comparator as you change a rule, its sorted columns weighted and numbered by level. Reset goes back to the page's own order, and the only Shine Button, Apply sort, re-sorts the drawn table and writes its chip, "Sort: Due date up, Priority down". For preview the dialog is drawn open in place when the page loads; the header button opens the real Dialog, with the same rules. For tables, task lists, inboxes and any list that has more than one way to be ordered.
FAQ
Why is the dialog already open, and what do I keep?
So you can see it without a click. On load the dialog is a copy drawn in place over the table: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Sort button opens the real Dialog, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same SortBody component and share the block's state, so the rules you set in the copy are there in the real one. In your app keep the Dialog and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
How does the tie-break work?
The first rule decides the order, the second only orders rows the first leaves tied, and the third only those still tied after it. Rows that tie on every rule keep the order the page loaded them in, so the sort is stable and the same on every device. Move up and Move down change which rule counts first. With Due date up and then Priority down, the two tasks due on Oct 16 are ordered Urgent before Medium; the preview's numbered column heads show which rule decides what.
Why can't I pick the same field twice?
A second rule on the same field could never break a tie the first one left, so the fields a rule already uses are unavailable in the others, and Add a level offers the first field that is still free. Priority sorts by rank, Low then Medium then High then Urgent, not alphabetically; Assignee and Title use a locale-aware comparison; Due date compares real dates.
What does the preview show on a phone?
The first five of the six rows, sorted as the rules say. On a phone the Assignee column folds into the Task cell as a second line, so a rule on Assignee is still visible. The sorted columns are weighted in the head and the cells and carry a number and an arrow, never a colour alone.
What stays local in the demo, and how do I wire it up?
All of it. The six tasks are a typed list and Apply sort only re-sorts the drawn table in this tab and says so in a polite message. In your app send the rules, a list of field and direction, to your API or sort a query with them, and keep the comparator for rows already on the page; Apply says "unchanged" instead of re-running when nothing differs.
Is it accessible from the keyboard?
Yes. The real dialog is named by its title and described by its sentence, focus starts on the first field and stays inside until the dialog closes, and Escape, Cancel and the close button return focus to Sort. The rules are a labelled list of native selects and segment groups, each named for its field, and every move is said in a polite message. The trigger is passed to DialogTrigger through render, and the dialog is controlled with open and onOpenChange. The copy shown on load moves no focus; Escape inside it, Cancel and its close button close it and put focus on the button.
Related
- Pro
Reorder Items Dialog
Notes and editingA landing-page builder's reorder dialog shown open: five page sections with grips you lift with Space and move with the arrow keys, Move up and down buttons, a spoken position, and the page behind it rearranging on save.
- Pro
Filter Sort Dialog
Side sheetsA vinyl shop's records page with its filter panel shown open as a sheet from the start edge: genre chips, a decade list, a two-thumb price range, conditions, an in-stock switch and a sort order, all changing the grid behind it as you touch them.
- Pro
Sortable Members Table
Sort and searchA members table whose column heads are buttons: press one to sort, again to reverse, a third time for the original order, with aria-sort on the active head, ties settled by name and a spoken line for each result.
- Pro
Column Reorder Table
Columns and pagingA pipeline table with a Column order list beside it: Move earlier and Move later buttons reorder the columns and announce the move, a grip drags as an extra, and Reset restores the default order.
- Pro
Table Insert Dialog
Drawers and popoversA team wiki's table picker shown open under its toolbar: an eight by eight grid of buttons that grows with hover and the arrow keys, the size said in words, a header-row switch, and a drawn table landing at the cursor.
- Pro
Tag Manager Dialog
Pickers and searchAn expense tracker's tag dialog shown open: a search, a create row with five swatches, a list of eight tags you rename in place, merge or delete after a confirm, an always-there Undo, and the drawn transactions following.