Filters & parameters

Filters write into a central reactive store; any query that references the filter's name with ${...} re-runs when it changes. The selection is mirrored to the URL, so a filtered view is shareable and bookmarkable.

Pick a channel above — the chart re-queries. The '${channel}' = '' guard makes "no selection" mean "all".

The filter components #

Component Purpose
<Dropdown> Single- or multi-select (multi). Multi feeds IN (…).
<Combobox> Searchable single-select for high-cardinality columns (server-side search). See Combobox.
<Search> A free-text filter value.
<DateRange> A start/end date pair with presets.
<RangeSlider> A numeric low/high range, dual-handle slider. See RangeSlider.
<Slider> A single-value numeric threshold, one-handle slider. See Slider.
<ButtonGroup> A single-select segmented control for a few fixed options. See ButtonGroup.
<Toggle> A boolean on/off switch — "show only X". See Toggle.

Note

Filter controls drive server-side SQL substitution, so they can't re-query a fixed snapshot. dashdown build strips them from static exports automatically. The full-text <SiteSearch> is not a filter — it searches a static index and ships in exports.

Where filters appear #

A filter renders inline, exactly where you place it in the Markdown. So you can drop a <Dropdown> directly above the one chart it controls — like the Channel picker above — and it stays there:

## Revenue by region

<Dropdown name="region" data={regions} column="region" label="Region" />

<BarChart data={revenue} x="month" y="revenue" series="region" />

To gather page-wide filters into a single row at the top instead, add bar:

<DateRange name="period" bar />
<Dropdown name="region" data={regions} column="region" bar />
<RangeSlider name="price" min={0} max={1000} bar />
<ButtonGroup name="tier" options="High,Mid,Budget" bar />
<Toggle name="paid" label="Paid only" bar />
<Search name="q" bar />

Controls marked bar collect into a filter bar below the page title. When more than three are present the extras fold into a "Filters" drawer, and the bar shows dismissible active-filter chips with a "Clear all". Frontmatter filters: drawer sends every bar control straight to the drawer:

---
filters: drawer
---

Tip

Mix freely: keep the one dropdown a chart depends on inline next to it, and lift the page-wide date range and search into the bar. A page with no bar controls has no top filter row at all.

Global date filter #

Unlike the filter components above (placed per page in your Markdown), the global date filter is a single date-range control shown in the app header on every page, applying project-wide. Configure it once in dashdown.yaml:

global_filters:
  date:
    enabled: true                 # off by default — this turns it on
    label: Period                 # the control's label
    default: last_30_days         # preset applied on a visitor's first load
    presets: last_7_days,last_30_days,last_90_days,this_month,this_year,custom
    start_param: date_start       # the ${param} names your queries reference
    end_param: date_end

Only enabled: true is required; every other key has the default shown above.

Queries opt in purely by convention — any query whose SQL references the configured ${date_start} / ${date_end} placeholders is filtered; queries without them are untouched. There's no backend query rewriting; the control just writes those two params into the filter store and the normal re-fetch path does the rest.

SELECT day, SUM(downloads) AS downloads
FROM downloads
WHERE day BETWEEN '${date_start}' AND '${date_end}'
GROUP BY day
ORDER BY day

Tip

The control appears only on pages whose queries actually reference those params — a docs or non-date page shows no dead control, while the persisted selection still applies once you navigate to a date-aware page.

Placement & persistence. On a normal page the control lives in the sticky app header (reachable even when scrolled). The selection persists across navigation (localStorage), so it behaves as one global filter rather than a per-page one — URL params still win over the remembered value. When a page is embedded (?_embed) the header chrome is omitted, so the control renders as an ordinary filter in the filter bar instead. Static builds omit it (a fixed snapshot can't be re-filtered), like the other filter controls.

It reuses the same control as the <DateRange> component, so presets, the custom range picker, and URL sync all behave identically.

Generated