Interactive Board Example¶
A board with variables and filters that update charts dynamically, built on the Dundersign demo dataset; paste it into the playground and it renders as-is.
Complete Board¶
title: "Document Activity with Filters"
source: db
variables:
status:
input: select
options:
static: ["sent", "completed"]
# No default: starts on All statuses
date_range:
input: daterange
# No default: starts on the full history
min_pages:
input: slider
min: 1
max: 20
step: 1
default: 1
queries:
filtered_documents:
sql: |
SELECT
status,
COUNT(*) AS documents,
ROUND(AVG(page_count), 1) AS avg_pages,
ROUND(AVG(days_to_complete), 1) AS avg_days_to_complete
FROM dundersign.documents
WHERE {{ filter('status', status) }}
AND {{ filter_date_range('created_at', date_range) }}
AND {{ filter('page_count', min_pages, '>=') }}
GROUP BY status
ORDER BY documents DESC
monthly:
sql: |
SELECT month, revenue, active_users
FROM dundersign_serving.monthly_metrics
WHERE {{ filter_date_range('month', date_range) }}
AND month > (SELECT MIN(month) FROM dundersign_serving.monthly_metrics)
AND month < (SELECT MAX(month) FROM dundersign_serving.monthly_metrics)
ORDER BY month
rows:
- title: "Filtered Document View"
grid:
columns: 24
items:
- item: documents_chart
width: 12
- item: revenue_chart
width: 12
- item: documents_table
width: 24
charts:
documents_chart:
title: "Documents by Status"
query: queries.filtered_documents
type: bar
x: status
y: documents
revenue_chart:
title: "Revenue by Month"
query: queries.monthly
type: line
x: month
y: revenue
documents_table:
title: "Status Details"
query: queries.filtered_documents
type: table
Note how date_range is wired into both queries: one variable can drive
any number of charts.
How Variables Work¶
Variable Definition¶
Variables are defined at the board level:
variables: status: input: select options: static: ["sent", "completed"] # No default: starts on All statuses
input: The UI component (select, slider, daterange, etc.)options: Available options (static list or dynamic query)default: Initial value; omit it to start unfiltered
Wiring Variables to Queries¶
Variables are referenced in the query SQL: the filter() helper skips the
condition entirely when its variable is unset:
queries: filtered_documents: sql: | SELECT status, COUNT(*) AS documents FROM dundersign.documents WHERE {{ filter('status', status) }} AND {{ filter_date_range('created_at', date_range) }} AND {{ filter('page_count', min_pages, '>=') }} GROUP BY status
When a variable changes, the query automatically re-executes with the new values.
User Interaction Flow¶
- User selects status from dropdown →
statusvariable updates - User adjusts date range →
date_rangevariable updates - User moves slider →
min_pagesvariable updates - Query re-executes with new filter values
- Charts update automatically with new data
Key Concepts¶
Handling "All" Values¶
When a variable can be "All", filter() already does the right thing for an
unset value, and a non-required select or multiselect already offers a
clear-selection row back to that unset state, so most boards need nothing
further. If you want "All" to instead appear as one of the visible, selectable
options in the list, use a Jinja conditional in the SQL:
This shows all statuses when "All" is selected, otherwise filters to the selected status.
Multiple Variable Types¶
This example shows three common variable types: - Select: Single choice dropdown - Date range: Date range picker - Slider: Numeric range input
Grid Layout with Multiple Charts¶
Using grid layout to show multiple charts:
grid: columns: 24 items: - item: documents_chart width: 12 - item: revenue_chart width: 12 - item: documents_table width: 24
Extensions¶
Add More Variables¶
Add additional filters:
variables: priority: input: multiselect options: static: ["low", "normal", "high", "urgent"] default: ["high", "urgent"]
Dynamic Options¶
Load options from a query:
variables: template: input: select options: query: queries.template_list
Related¶
- Variables Guide - Learn about variables
- Expressions Guide - Learn about variable references
- Drill-Down Example - Planned click filtering