Filters & Inputs
Add filters, controls, and option lists.
Inputs let users change what a Data App shows. The two main input types are:
- filters, which constrain data, such as Campaign, Region, State, or Date Range;
- controls, which change query shape, such as time grain, selected measure, or top-N limit.
This page focuses on filters and option lists.
Filter Input
A filter input points at a field.
const campaignInput = useSemaphorInput({
id: 'campaign',
label: 'Campaign',
kind: 'filter',
field: campaignId,
operator: 'in',
multi: true,
});Pass the input handle to a query:
const result = useSemaphorQuery(revenueByCampaign, {
inputs: [campaignInput],
});If campaignInput is active, Semaphor applies it server-side.
Option Query
Dropdowns need option values. Use semaphor.inputOptions.
const campaignOptions = semaphor.inputOptions({
id: 'campaign_options',
inputId: 'campaign',
source: campaign,
labelField: campaignName,
valueField: campaignId,
searchField: campaignName,
limit: 100,
});The user sees labelField. The input stores valueField.
labelField: campaign_name -> "Holiday Retargeting"
valueField: campaign_id -> "cmp_123"Prefer stable ids as values. Labels can change or duplicate.
Same-Source Cascading Filters
Use the same source for simple hierarchy filters. For example, Region and State live in dim_geo.
const geo = semaphor.source.semantic({
domainId: 'commerce',
datasetName: 'dim_geo',
});
const regionId = semaphor.field.id('region_id', { source: geo });
const regionName = semaphor.field.dimension('region_name', { source: geo });
const stateId = semaphor.field.id('state_id', { source: geo });
const stateName = semaphor.field.dimension('state_name', { source: geo });Region options:
const regionOptions = semaphor.inputOptions({
id: 'region_options',
inputId: 'region',
source: geo,
labelField: regionName,
valueField: regionId,
});State options:
const stateOptions = semaphor.inputOptions({
id: 'state_options',
inputId: 'state',
source: geo,
labelField: stateName,
valueField: stateId,
});By default, option dependencies are auto: compatible active inputs narrow each other. If Region is South, State options only show southern states. If State is Texas, Region options can narrow to South.
No automatic value propagation
Cascading filters narrow option lists. Selecting Texas should not automatically select South. It can make South the only Region option, but it should not change another input value unless the user does it.
Clearing Stale Child Values
If Region changes from Northeast to South, a previously selected State such as New York is stale. Use useClearInvalidSemaphorInputValue after the child option query succeeds.
import {
useClearInvalidSemaphorInputValue,
useSemaphorInput,
useSemaphorQuery,
} from 'react-semaphor/data-app-sdk';
function StateFilter() {
const stateInput = useSemaphorInput({
id: 'state',
label: 'State',
kind: 'filter',
field: stateId,
operator: 'in',
multi: true,
});
const options = useSemaphorQuery(stateOptions);
useClearInvalidSemaphorInputValue(stateInput, options);
return <StateSelect input={stateInput} options={options.options} />;
}Only a successful option result is authoritative. Loading or failed option queries should not clear a valid persisted value.
Date Range Filter
A date range is a filter with operator: 'between'.
const dateRange = useSemaphorInput({
id: 'date_range',
label: 'Date Range',
kind: 'filter',
field: orderDate,
operator: 'between',
defaultValue: ['2026-01-01', '2026-01-31'],
});For multi-source dashboards, use one date range input but bind each view to its own modeled date field. For example:
orders view -> fact_orders.order_date
tickets view -> fact_support_tickets.created_date
usage view -> fact_product_usage.usage_dateThe planner or generated app should use the primary date field from the semantic model when available.
Shared Inputs Across Views
One visible input can drive multiple queries. Keep the same user-facing input, then bind it to the field each query should use.
const dateRangeInput = useSemaphorInput({
id: 'date_range',
label: 'Date Range',
kind: 'filter',
field: purchaseDate,
operator: 'between',
});
const purchaseTrend = semaphor.records({
source: purchaseLine,
fields: [purchaseDate, netPurchaseValue],
inputs: [
semaphor.bindInput(dateRangeInput, {
field: purchaseDate,
operator: 'between',
}),
],
});
const salesTrend = semaphor.records({
source: salesLine,
fields: [saleDate, salesValue],
inputs: [
semaphor.bindInput(dateRangeInput, {
field: saleDate,
operator: 'between',
}),
],
});Use the same pattern for conformed dimension filters. For example, one Material Family input can filter both purchase and sales facts when each query provides the appropriate source-bearing field and relationship hint.
Keep the visible input stable
semaphor.bindInput(...) does not create another control. It maps the same input value to the field and relationship that a specific query needs.
Searchable High-Cardinality Options
For customers, SKUs, users, invoices, or orders, do not load all options.
const customerOptions = semaphor.inputOptions({
id: 'customer_options',
inputId: 'customer',
source: customer,
labelField: customerName,
valueField: customerId,
searchField: customerName,
limit: 50,
});Pass a search string from your combobox to the option query when your UI supports typeahead.
Controls
Controls change query shape instead of filtering rows.
const grainControl = useSemaphorInput({
id: 'grain',
label: 'Time Grain',
kind: 'control',
role: 'grain',
defaultValue: 'month',
options: ['day', 'week', 'month', 'quarter'],
});Common control roles:
| Role | Example |
|---|---|
grain | day, week, month, quarter |
measure | revenue, gross margin, quantity |
dimension | campaign, region, category |
aggregation | sum, average, count |
sqlParam | explicit parameter for a SQL fallback query |
Input Design Checklist
- Use ids for
valueFieldwhen possible. - Use labels for
labelField. - Add
searchFieldfor large lists. - Add
disambiguationFieldswhen labels can duplicate. - Let option dependencies default to
autounless you intentionally needindependentorexplicit. - Use server-side option queries. Do not fetch all options into the client for filtering.