ADR-0015: FilterableFolderContent — custom Quartz component for frontmatter-driven folder filtering
Status: Accepted Date: 2026-05-20
Context
Two vault folders need client-side filtering on the published Quartz site:
/questions/— filter bypriority:(critical | interesting | minor)/reference/— filter by source resource class (BR, DP, CSG, …) extracted fromsources:wikilinks
The default FolderContent Quartz component renders a flat list with no filtering capability.
Decision
Create a custom FilterableFolderContent component that replaces FolderContent as the pageBody for folder pages. It renders pill buttons above the file list and uses client-side JS to show/hide list items based on the active filter. URL query params are kept in sync so filters are deep-linkable and shareable.
Configuration lives in quartz.config.ts via Plugin.FolderPage({ pageBody: FilterableFolderContent({...}) }). The FolderPage emitter already spreads userOpts after its default pageBody, so no emitter code needs modification.
Filter values are auto-discovered from allFiles at build time. An optional displayNames map allows short labels (e.g. "Believers-Responsibility" → "BR"). For multi-value array fields (like sources:), an extractKey function pulls the resource class prefix from each wikilink.
Alternatives considered
- Emitter generating static per-value pages (e.g.
/questions/priority/critical/): Rejected. Multiplies page count, breaks single-canonical-URL convention, doesn’t compose with multi-value fields likesources:. - Separate
beforeBodyfilter pills + existingFolderContentlist: Rejected. No structured data hook on list items without modifyingFolderContent’s HTML output — cross-component DOM coordination is fragile. - Tag-page mirror: Rejected in prior session (Q4) as too coarse; doesn’t generalize across field types.
Upgrade resilience
Quartz is vendored at _meta/quartz/ and updated via manual re-clone + diff. Our customizations:
- 2 new files (
FilterableFolderContent.tsx,folderFilter.inline.ts) — not in upstream; copy them back after re-clone - 2 lines in
index.ts— one import, one export; trivial to re-apply quartz.config.ts— user config, never overwritten by upgrades
Custom files to re-apply after Quartz re-clone:
quartz/components/pages/FilterableFolderContent.tsxquartz/components/scripts/folderFilter.inline.ts
Risk: if Quartz significantly changes FolderContent’s HTML/CSS structure, our component’s rendering may diverge visually. Acceptable: we own the file and can update it.
Consequences
- (+) Readers can filter
/questions/by priority and/reference/by source with no page reload - (+) Deep-linkable URLs (
/questions?priority=critical) - (+) Generalizes to any frontmatter field on any folder with minimal config
- (+) Upgrade-safe: 2 new files + 2-line change in vendored index
- (−) Component must replicate
FolderContentlist HTML structure — small maintenance surface if upstream HTML changes