Skip to content
shadcn.io

shadcn.io is not affiliated with official shadcn/ui

Sortable Members Table Block for React

A 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.

Framework
UI library

Preview

Preview width

Installation

Part of Pro
Pro unlocks the code and one-line install of every Pro button and text effect, plus the MCP for your AI editor.
Have Pro already? Sign in to open it.Opens here as soon as you're Pro.

Overview

Let people put a table in the order they need, with this sortable members table for React with Base UI. A compact header names the table and, below the medium breakpoint, holds a Native Select to sort by any column. Inside a hairline frame with a plus mark on each corner, a band names the table and says in words how it is ordered ("Sorted by last active, newest first"), over a native table of eight members: a name with an initials Avatar, a role, the rides logged, the date last active and an outline Badge whose dot is filled, half filled or hollow for Active, Away and Invited. Every column head is a button with an arrow. The first press sorts in the order that column starts with (names A to Z, rides and dates highest first), the second reverses it and the third puts the rows back in the order the members joined, and the active head says which way it points. The rows are the same eight in every order, so the table never changes height. On a phone the Role and Rides columns fold into the member's cell. It's built from Native Select, Avatar, Badge and Guides, with a CSS entrance only. For member lists, directories, admin consoles and any table with a few sortable columns.

FAQ

How do I fill it with my own rows and columns?

Edit MEMBERS, which is also the original order: the order a third press goes back to. Each column is a small Column constant (its key, its label, the order its first press gives and the words for each order), and gapOf says how two rows compare on a key. Add a column by writing its constant, a case in gapOf, a head with SortHead and a cell in the row. Dates are ISO strings written in UTC and formatted by day, so they read the same on the server and in every visitor's time zone.

What do the three presses do, and how are ties settled?

A head's first press gives the order that column starts with: names and roles A to Z, status active first, rides and dates highest first. The second press reverses it and the third returns the rows to the order they came in, so the table can always be put back. Rows that compare equal, such as two members last active on the same day, are ordered by name in both directions, so an order never depends on how the browser happens to sort. The result is applied on the press and never while the pointer is over a row, so nothing moves under the cursor.

What stays local, and how do I sort on a server?

Everything happens in the page: the sort lives in one useState, sortRows reorders the typed rows and nothing is saved or requested. For a long list, keep nextSort and the heads as they are and send the sort (seen:descending) to your API in the press handler, render the rows it returns, and leave the rest of the table alone. The same state also drives the "Sort by" menu, the aria-sort values and the spoken line, so wiring it once wires all of them.

Is a table with sort buttons accessible?

Yes. It's a native table with a caption, th scope="col" heads and a row header for each member. The sorted head carries aria-sort="ascending" or "descending" and the others say none, so a screen reader announces the order as you move along the heads. Each head holds a real button named by its label, so it takes Tab, Enter and Space with a visible focus ring, and the arrow is decorative. A polite status line, present from the start, says what happened after each press ("Original order, as members joined."). The table region is focusable so it can be scrolled by keyboard if it ever overflows. It is the same native table on every library, so it behaves the same on every target.

How does it look on a phone?

Below the medium breakpoint the Role and Rides columns fold into a second line under the member's name ("Mechanic, 164 rides"), the avatar goes and the table keeps Member, Last active and Status, so nothing scrolls sideways. The hidden columns can still be sorted: the "Sort by" menu in the header lists every column in both orders, and it follows the heads, so choosing "Rides, most first" in the menu and pressing the Member head land on the same state.

Does the table change height when it is sorted?

No. The set of rows never changes, every row keeps the same lines whatever its place, and the status line has its own height, so the frame stays the same size. The rows are rebuilt for each order, so there's no row sliding about. If you add filtering or paging to your own table, keep the frame's height with a fixed region or an unseen copy of the longest state.

  • Pro

    A customer segments table ordered by a two-rule sort builder: pick a column and a direction for the first rule and for the tie-break, see the order as a 1 and a 2 on the heads, and Reset to start again.

  • Pro

    A ticket queue where a switch raises any ticket due within two days by one level, shown as drawn bars, a word and a raised-from note, and the Priority head sorts by that effective rank.

  • Pro

    A library catalogue table with a search field and an availability menu: typing keeps the titles whose name or author holds the words and marks them, the foot says how many match, and an empty state under the head clears the search.

  • Pro

    Chip Filters Table

    Sort and search

    A bug table beside a rail of chip filters for priority and status: chips in a group are or, the groups are and, every chip counts what it would show, and an empty state clears them all.

  • Pro

    A table of services in a tinted frame with sortable column heads, 30-day uptime strips, response times and error rates, and a mark and a word on any service that is down.

  • Pro

    Dependency Updates Changelog

    Packages and versions

    A table of eight dependency updates in two groups, Production and Dev: package, old and new version, the kind of bump and a three-pip risk, with sortable heads that reorder the rows inside each group.