Skip to content

shadcn.io is an independent project built on shadcn/ui

Free

Sort Controls Button Group for Svelte

Sort by Name, Date, or Size, with an arrow that flips direction, plus Price, Rating, and Popular.

UI library: Ark UI

Two rows share one field and one direction, starting at Name, ascending. The first is Name, Date, and Size, then an arrow that flips direction. The second is Price, Rating, and Popular, and the selected field shows that arrow. Picking Price clears Name. The demo sorts nothing.

Use a separate arrow when every field can flip, and the in-button arrow when only the active field should show it. A long field list fits a Select. In Svelte, Ark UI does not reorder the rows.

Preview

Preview width

Installation

MCP · Pro
Make your AI a shadcn expert
Your agent installs components, builds pages and restyles your app from one prompt, in Claude Code, Cursor or VS Code.
Part of Pro

Anatomy

Button Group anatomy: root, group, button, separator

Usage

<div class="flex flex-col gap-4"><ButtonGroup aria-label="Sort by">{#each FIELDS as item (item.value)}<Button aria-pressed={sortField === item.value} onclick={handleField} size="sm" value={item.value} variant={sortField === item.value ? "default" : "outline"}>{item.label}</Button>{/each}<Button aria-label={sortOrder === "asc" ? "Sort ascending" : "Sort descending"} onclick={toggleOrder} size="icon-sm" variant="outline">{#if sortOrder === "asc"}<ArrowUpIcon aria-hidden="true" />{:else}<ArrowDownIcon aria-hidden="true" />{/if}</Button></ButtonGroup><ButtonGroup aria-label="Sort products by">{#each PRODUCT_FIELDS as item (item.value)}<Button aria-pressed={sortField === item.value} onclick={handleField} size="sm" value={item.value} variant={sortField === item.value ? "default" : "outline"}>{item.label}{#if sortField === item.value && sortOrder === "asc"}<ArrowUpIcon aria-hidden="true" data-icon="inline-end" />{/if}{#if sortField === item.value && sortOrder === "desc"}<ArrowDownIcon aria-hidden="true" data-icon="inline-end" />{/if}</Button>{/each}</ButtonGroup></div>

FAQ

What is tracked?

Two values: the field, starting at name, and the direction, asc or desc, starting at asc. Every field button stores its own value as the field.

How does the direction button work?

It flips between ascending and descending and shows an up or down arrow. Its aria-label says Sort ascending or Sort descending, so the icon-only button has a name.

How does the second row show the direction?

The selected field's button adds an arrow after its label. The other buttons show no arrow. The direction itself only changes from the first row's arrow button.

Do the two rows share the field?

Yes. Picking Price clears Name. Use separate values if both rows should stay set.

How is the sorted field shown?

Its button uses variant="default" and aria-pressed. The rest use outline.

Does the demo sort anything?

No. Sort your rows by the field and direction where you render them.

API Reference

Button Group

Sets aria-label="Sort by" and aria-label="Sort products by". The rest is on the Button Group page.

Button

Sets aria-pressed={sortField === item.value}, onclick={handleField}, size="sm", value={item.value}, variant={sortField === item.value ? "default" : "outline"} and aria-label. The rest is on the Button page.