-
Notifications
You must be signed in to change notification settings - Fork 0
Facet Type Matrix
An intersection picker. Stack several values and results narrow to items that carry every one — AND-within-facet, made legible.
A list of rows, one per value, each with a toggle, a selected-state dot, and a per-row count bar sized to that value's share of the largest bucket. Selecting rows stacks them: the resolver ANDs the selected values together, so an item must carry all of them to survive. Pair it with the active-filters chip strip so shoppers can see exactly which values are stacked.
Unlike a checkbox facet (which defaults to OR within the facet), the matrix display defaults to AND — that's the whole point of an intersection picker.
- "Show me items that are both organic and cotton and fair-trade"
- Attribute stacking where each added value should narrow, not widen, results
- Surfacing how many items each value contributes via the count bars
- You want OR semantics (match any selected value) → use Checkbox
- Single-select → use Radio
- Long lists where the count bars add noise → use Checkbox
The display slug is matrix.
{
"name": "features",
"kind": "taxonomy",
"source": "pa_features",
"display": "matrix",
"label": "Stack features"
}| Field | Values | Default | What |
|---|---|---|---|
settings.match |
"any" | "all"
|
"all" |
all = AND within the facet (item must carry every selected value); any = OR. Matrix defaults to all
|
The matrix display is the only facet that defaults settings.match to all.
The resolver applies this default in Resolver::build_facet_legs() — when
match resolves to all it emits one single-value INTERSECT leg per selected
value, so the object must match all of them. The match setting is read from
the shared settings allowlist in src/Api/RestController.php; there are no
other matrix-specific settings.
| Input | Action |
|---|---|
| Toggle a row | Adds/removes that value from the stacked set, then refetches |
| Selected row | Shows a filled dot and a highlighted cell |
| Count bar | Tracks the row's share of the largest bucket count |
Each row is a real checkbox, so the runtime reuses the multi-select path; the matrix is the UI, the AND semantics live in the resolver.
?hof[features][]=organic&hof[features][]=cotton
Array form, same wire shape as a checkbox facet. The any/all match mode lives in the facet config, not the URL — so the same link works regardless of match mode.
The per-row count bar reads a runtime-set custom property; the rest uses the
shared --hof-* tokens:
.hof-matrix-bar {
/* width tracks the row's share of the largest bucket count */
width: calc(var(--hof-matrix-weight, 0) * 60px);
}--hof-matrix-weight is written per row by the renderer (the value's count
divided by the largest count). Selected cells and the dot pick up
--hof-primary.
hooked on facets · Filtering, finally fun. · GitHub · hookedonfacets.com
Filtering, finally fun.
📖 docs
🧠 concepts
🎛️ facet types
- All Types
- Checkbox
- Radio
- Dropdown
- Range Slider
- Date Range
- Search
- Hierarchy
- Color Swatch
- Swipe Deck
- Spin the Wheel
- Intersection Matrix
- Ask
- Visual DNA
- Toggle
- Saved Bin
- Pagination
🔧 develop
🗺️ project