Components · Data

Filter

Filtering is the only component in this system whose entire job is to hide clinical information. That makes it the one that most needs to be honest: what is hidden, how much of it, and how to get it back — visible at all times, in one glance, without opening anything.

Stable · v1.0 shadcn/ui WCAG 2.2 AA IEC 62366-1

Overview

A clinician who forgets a filter is on is looking at a subset of a patient's record while believing they are looking at the record. Every rule here follows from that single failure: filters are loud, counted and reversible.

The system's default position is that filters are a convenience for large sets, not a workflow. They never persist silently, never survive a patient change, and never apply to anything at advisory priority or above.

Always visible

Active filters render as tags above the data they act on. Never a count in a button, never a coloured icon, never only inside a panel.

Always counted

4 of 19. The hidden quantity is stated as a number, next to the data, at all times.

Never hides an alarm

No filter, of any kind, can remove an unacknowledged alarm at advisory priority or above from view.

Anatomy

Filters above the set they act on

Showing 4 of 19 patients · 15 hidden by filters

1 critical alarm outside your current filters
Bed 7 · ST elevation V2–V4 · unacknowledged
Shown regardless of filters · detected 15:41:02
PartRule
Add filter A single entry point. Opens a menu of dimensions, not a wall of always-visible controls that consumes the screen the data needs.
Filter tag One per active criterion, reading dimension: value in full. Removable individually with a labelled control.
Count line Required. n of N plus the number hidden, adjacent to the data, always rendered — not only when filtering is active.
Clear all States how many it will clear. One action returns the complete set.
Escape hatch Anything at advisory priority or above that the filter would have hidden is surfaced above the set, with a route to it.

What a filter may never hide

The rule that carries the risk

An unacknowledged alarm at advisory priority or above is not filterable. If a patient matching no active filter has one, the set reports it above the fold with a route to the patient. The clinician chose to narrow their view; they did not choose to stop being told about deterioration, and no filter UI is allowed to interpret it that way.

This is a governed behaviour. It has no configuration flag, no "advanced" setting, and no per-deployment override.

Persistence

A filter that outlives the clinician's memory of setting it is the hazard. So persistence is deliberately weak, and always announced.

BoundaryBehaviour
Within a view, same sessionFilters persist.
Navigating away and back Filters persist and the tag row is re-announced on return.
Patient changeCleared. Without exception.
New session or new userCleared. Filters are never part of a saved user profile that applies silently at sign-in.
Shift handoverCleared, and the handover view is never filtered — see Triage worklist.
Saved viewsPermitted, but a saved view is applied only by explicit selection and names itself in the tag row as a saved view.

States

StateRendering
None active Tag row absent; the count line still renders — 19 of 19. The absence of filtering is information too.
Active Tags visible, count line shows the hidden quantity, Clear-all states its count.
Applying The previous set stays on screen with an activity indicator. Filtering never blanks the region it is narrowing.
Zero results Empty state naming the responsible filters, with a one-action route back.
Filter unavailable The dimension is offered but marked unavailable with a reason. A dimension that silently disappears makes the clinician doubt the whole control.
Escaped item present The above-the-fold alarm callout, rendered whether or not the set is empty.

Do's and don'ts

Do
Ward: Emergency Awaiting review

Each criterion legible and separately removable, sitting directly above the data it narrows.

Don't

Two criteria hidden behind a number. The clinician can see that something is filtered, which is exactly the state that gets misremembered as nothing.

Do

Showing 4 of 19 patients · 15 hidden by filters

The hidden quantity as a number. Fifteen is a size the reader can weigh; "filtered" is not.

Don't

4 patients

A count with no denominator. Indistinguishable from a ward with four patients in it.

Do
1 critical alarm outside your filters — Bed 7

The filter narrowed the view, not the duty of care. The alarm escapes and says that it did.

Don't

Showing 4 of 19 patients

Correct, complete, and still wrong: one of the fifteen hidden patients has an unacknowledged critical alarm and nothing on screen says so.

Do
Arrived after 12:00

The criterion in the clinician's own words, complete enough to check against what they meant.

Don't
arrival_ts > 1200

A field name and a raw value. Unreadable under time pressure, ambiguous about time zone, and unlabelled for assistive technology.

Accessibility

Outcomes of use

What this contributes to, in the terms of Usability & context of use. These are attributes believed to contribute to an outcome; the outcome itself is settled by observing real use in a specified context, not by this page.

Clinical safety notes

Risk controls carried by this component

Trace these in your risk file (ISO 14971) and usability engineering file (IEC 62366-1).

Implementation

$ npx shadcn@latest add https://md.notjustany.tech/r/filter.json
// The escape rule is enforced in the component, not in each product's
// query layer, because it is the control that must not be forgotten.
<FilterBar
  label="Worklist filters"
  filters={active}
  total={19}
  shown={4}
  onRemove={remove}
  onClearAll={clearAll}
  escaped={escapedAlarms}        // items the filter would have hidden
/>

// Anything unacknowledged at advisory or above escapes the filter and is
// reported above the set. There is no flag to switch this off.
const escapes = (item) =>
  item.alarm && !item.acknowledged &&
  PRIORITY_ORDER[item.alarm] >= PRIORITY_ORDER.advisory

if (shown < total && escaped === undefined) {
  throw new Error("[FilterBar] a narrowed set must compute its escaped items.")
}
PropTypeNotes
filtersActiveFilter[] Required. Each carries dimension, displayValue and id.
total · shownnumber Required. Both, always — the count line renders even at 19 of 19.
escapedEscapedItem[] Required when narrowed. Items above advisory priority the filter excluded.
subjectIdstring Filters clear automatically when this changes.
savedViewNamestring Renders a leading tag identifying the saved view as the source.
NotJustAnyMed.Tech Design System · Filter · v1.0 · draft for review
Reference applications named in this system are fictional; all patient data and reference ranges shown are fabricated and illustrative.