{"slug":"filter-bar","meta":{"title":"Filter Bar","slug":"filter-bar","kind":"pattern","summary":"A row of controls above a collection that narrows it by attribute, with every active filter visible as a removable chip and the whole state carried in the URL.","problem":"Someone wants \"all overdue invoices owned by Dana\" — they know the attributes, not the name. Search cannot help, because there is no term to type. Without filters they scan the whole list, and without visible active filters they eventually forget what they are looking at.","family":["find","scan"],"data_shape":["collection","tabular"],"principles":["friction","orientation","progressive-disclosure"],"interaction":["filtering","selection"],"density":"medium","complexity":"medium","status":"stable","visibility":"public","use_when":["People describe what they want by attributes rather than by name.","The collection is too large to scan and too varied for one default view.","The same few narrowings are used repeatedly by the same people."],"avoid_when":["There are fewer than about fifteen records. Sorting is enough.","Only one attribute ever matters — then it is a set of tabs, which is cheaper and more visible.","Every user needs a different combination every time; consider saved views instead."],"alternatives":[{"slug":"global-search","when":"People know the name or the identifier of the thing they want."},{"slug":"saved-views","when":"The same combinations are rebuilt daily and deserve a name."}],"ask_leo":"Put a filter bar above this collection.\n\n- Offer filters for the attributes people actually narrow by. Do not add one\n  per column; every filter is a control everyone reads and most never use.\n- Show every active filter as a removable chip, with its value, next to the\n  controls. A filter that is on but not visible is how people end up\n  misreading a list.\n- Include a single \"Clear all\" that appears only when something is active.\n- Put the whole filter state in the URL so a view can be reloaded, bookmarked\n  and pasted to a colleague, and so returning from a record restores it.\n- Show the result count, and update it as filters change.\n- When a combination matches nothing, say which filters are active and offer\n  to clear them. Never show a bare empty list.\n- Keep sensible defaults visible rather than hidden: if the list defaults to\n  the current month, show that as a chip like any other filter.\n","related":[{"title":"Filterable Index with Slide-Out Detail Drawer","url":"/cookbook/filterable-index-with-detail-drawer","summary":"The implementation, filter bar and drawer together."},{"title":"Dense Operational Table","url":"/patterns/dense-operational-table","summary":"What sits below the bar, and why fewer columns beats more filters."}]},"body":"## Anatomy\n\n```\n┌─────────────────────────────────────────────────────────────┐\n│ Status ▾   Owner ▾   Date ▾            42 of 318 invoices   │\n│ ● Overdue ✕   ● Owner: Dana ✕                  Clear all    │\n└─────────────────────────────────────────────────────────────┘\n   ↑ active filters, visible and individually removable\n```\n\nThe controls are the easy half. The three that matter:\n\n1. **Chips for what is on.** The single most common failure is a filter applied\n   from a dropdown that then shows no trace of itself. People read a partial\n   list as if it were the whole one and draw wrong conclusions.\n2. **State in the URL.** It makes the view shareable, reloadable and — the part\n   people feel every day — restorable when they come back from a record.\n3. **A count.** \"42 of 318\" is orientation: it says both how much you have and\n   how much you excluded.\n\n## Why it works\n\nIt serves a different question from search. Search answers *where is this\nspecific thing*; filters answer *which of these things match a description*. A\nproduct that offers only one of the two leaves half its users scanning.\n\nChips are what make it safe. A filtered list looks exactly like an unfiltered\none, so the interface has to say which it is — otherwise the person who inherited\nsomeone else's saved link reports a data problem that is really a filter.\n\nPutting the state in the URL is the quiet upgrade. It turns a transient UI state\ninto something a person can send in a message, which is how most real\ncollaboration on a list actually happens.\n\n## Getting it wrong\n\n- **Invisible active filters.** The list is wrong and nothing on screen says so.\n- **A filter per column.** Filters are a shared cost: everyone reads them, few\n  use each one. Add the ones people ask for, not the ones the schema permits.\n- **Filter state only in memory.** Reload, or come back from a record, and the\n  work is gone — see [back link](/patterns/back-link).\n- **A bare empty state.** \"No results\" with active filters and no way to clear\n  them is a dead end.\n- **A hidden default.** A list quietly scoped to this month, with nothing saying\n  so, produces confident wrong answers.\n\n## Exemplars\n\n**Linear's filter bar** builds up as chips, each one editable in place, and the\nwhole set is one click from being saved as a view. It shows the natural\nprogression: filters that keep getting rebuilt want a name.\n\n**Stripe's payments filters** are notable for restraint — a handful of\nattributes on a record type with dozens of fields — and for putting everything\nin the URL, so support conversations happen by pasting a filtered link.\n\nThe extractable rule: **a filter bar's job is to make the current scope\nundeniable.** Narrowing the list is the easy part; saying so, permanently and\nvisibly, is what keeps people from misreading it.\n"}