shadcn.io is not affiliated with official shadcn/ui
Filter Sort Dialog Block for React
A 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.
Installation
Overview
Let people narrow a shop without losing sight of it, with this filter panel for React with Base UI. It opens from the Records page of Groovecrate, a second-hand vinyl shop: the page's header holds an outline Filters Button that counts the filters on, and the page, a toolbar and 36 drawn sleeves, is shown under a soft scrim inside a hairline frame with a plus mark on each corner. The panel is a Sheet from the start edge, whichever way the page reads. It holds two quick picks that set everything at once, genre chips in a multiple Toggle Group, a Select for the decade, a Slider with two thumbs for the price, Checkboxes for the condition, a Switch for in stock only and a Radio Group for the order. Every control changes the page behind it as you touch it: the toolbar says how many of the 36 records show with a chip for each filter, and the sleeves line up in the chosen order with the matches first and the rest dimmed, so the grid never changes height. Show 23 records, the only Shine Button, counts what you would see and closes the sheet. For preview the panel is drawn open in place when the page loads; the header button opens the real Sheet, with the same controls and the same state. For shops, catalogues, tables and any list that people narrow.
FAQ
Why is the sheet already open, and what do I keep?
So you can see it without a click. On load the panel is a copy drawn in place over the page: a native dialog element that isn't modal, so nothing is trapped, hidden or focused, and the page around the preview keeps working. The Filters button opens the real Sheet, modal, with its focus trap, Escape and focus return, and the copy stays closed until a reload. Both show the same FilterFields component and share the block's state, so a filter set in the copy is there in the real one. In your app keep the Sheet and drop the copy: the "in-place" state, the scrim and the dialog element inside the frame.
Why does the sheet come from the start edge?
The catalog's sheet sides are physical, a left and a right, so in a right-to-left page a "left" sheet would open at the wrong edge. The block reads the page's direction when the sheet opens and picks the side that is the start of the line, which is the left in English and the right in Arabic or Hebrew. On a phone it fills the width. The copy shown on load uses logical positions, so it is at the start edge on its own.
Do the controls apply as I touch them, and what do the counts say?
Yes. There is no Apply step: the controls write to one filters value and the page behind the sheet reads it, so the toolbar and the sleeves follow at once. shownOf is the one pure function that filters and sorts the 36 records in ROWS, so the toolbar, the sleeves and the number on the foot button always agree: "Show 1 record" has one match and the toolbar says "1 of 36 records". The Filters button counts how many groups of controls are away from their start, so it is zero when nothing is on, and Clear all puts everything, the order too, back.
Why are the other sleeves dimmed and not hidden?
So the grid never changes height: a filter that hid sleeves would pull the page up and down as you touched controls. The matches come first in the chosen order and the rest follow, dimmed, in the same order. The sleeves are drawn shapes, one per genre, and are hidden from screen readers; the toolbar's count and chips carry the same facts as text, and the polite status message reports a quick pick, Clear all and Show.
Does it fetch anything, and how do I wire a real list?
No. The 36 records are typed in the file and filtered in the browser, and Show 17 records only closes the sheet. In your app keep filters as the state, build your query string or request from it when it changes, and show the count your API returns on the foot button; keep the dimming for a list that already holds every row, and remove rows for a paged one.
Is it accessible from the keyboard?
Yes. The real sheet is named by its title and described by its sentence, focus starts on the first quick pick and stays inside until it closes, and Escape and the close button return focus to Filters. The trigger is passed to SheetTrigger through render, and the sheet is controlled with open and onOpenChange. The genre chips and the order are groups you move through with the arrow keys, each price thumb is named and moves with the arrows, and the copy shown on load moves no focus; Escape inside it and its close button close it and put focus on Filters.
Related
- 12Pro
Sort Options Dialog
Notes and editingA 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.
- Pro
Filter Sidebar Gallery
Filter, sort and tabsA sidebar of category checkboxes with counts, a two-thumb price slider and a minimum rating select beside twelve drawn lights, with a Sheet for the filters on phones.
- Pro
Advanced Sort Reviews
Filter and searchA filter panel for tent reviews: a sort key, an order, star pills, a recency segment and a verified Switch beside the matching reviews, with removable chips, a live count and a bottom Sheet on phones.
- Pro
Apply Coupon Dialog
Payments and plansA cookware shop's basket with its promo-code dialog shown open: one field that judges five typed codes with five different answers, applied codes kept as removable chips, and a summary that is worked out again after every change.
- Pro
A hardware shop's quantity dialog shown open: a number field with a button on each side over a four-tier price ladder that follows it, a hint to the next tier and totals worked out in whole cents.
- Pro
Assign Task Dialog
Side sheetsA sprint board with a side sheet that assigns its one unowned task shown open: five people with their open tasks and load, a priority, a due date from chips or an inline calendar, and a switch to notify the assignee.