docs-mintlify/docs/explore-analyze/dashboards/widgets/controls.mdx
Controls are widgets that let dashboard viewers change what's shown without leaving the dashboard. The dashboard builder offers four control types:
The first three each target a member from your semantic model, and apply the viewer's choice to every chart on the dashboard whose query references that member. Filters and time granularity switchers change how a member is queried — which rows come back, which buckets they fall into. A field switcher goes further and changes which member is queried at all. A parent control works one level up: it targets no member of its own and drives other controls instead.
Filter widgets let viewers narrow down the data shown on the dashboard. In the dashboard builder, open the Add Controls menu in the toolbar and choose Filter. The new filter is added in an unconfigured state — click Configure Filter (or open the widget's settings menu) to pick a semantic view and a dimension.
The available operators depend on the type of the underlying dimension:
| Dimension type | Operators |
|---|---|
| String | is, is not, contains, not contains, starts with, not starts with, ends with, not ends with, is null, is not null |
| Number | is, is not, greater than, greater than or equal, less than, less than or equal, is null, is not null |
| Time | is, is not, before date, before or on date, after date, after or on date, between, relative date, is null, is not null |
Filters can allow either a single value or multiple values. Configure this when adding or editing the filter — multi-select is the default for string dimensions, while time and number dimensions default to a single value.
You can set a default value that's applied when the dashboard loads. Defaults are useful for scoping the dashboard to "this quarter" or "the user's region" without requiring viewers to interact with the filter first.
There are two ways to set a default:
Static defaults are configured by interacting with the filter in the dashboard builder — the value you select is saved on the widget and applied to every viewer when the dashboard loads.
Use the User attribute default toggle in the filter's edit sidebar to pre-fill a filter from the viewer's user attribute. When the dashboard loads, Cube looks up the attribute value for the current viewer and applies it as the filter's default.
This is useful for scoping a dashboard to the viewer's own slice of the data — for example, defaulting a Region filter to the viewer's region attribute, or a Sales rep filter to their email.
To configure it:
<Steps> <Step title="Open the filter's settings"> In the dashboard builder, click the filter widget's settings menu and choose **Edit Filter**. </Step> <Step title="Enable User attribute default"> Scroll to the **User attribute default** switch and turn it on. </Step> <Step title="Pick the attribute"> Select the [user attribute][ref-user-attributes] whose value should be used as the default. Only attributes defined in your account appear in the picker. </Step> </Steps>How the attribute value is matched to the filter:
| Attribute type | How it's applied |
|---|---|
| String, Number | Used as a single value. Works with single-value operators like is / is not, and is also accepted by multi-select filters as a one-item selection. |
| String array, Number array | Used as a list of values, one per array entry. Empty values are dropped. |
Empty, null, or unresolvable attribute values are skipped — the filter falls back to whatever static default it has, or no default if none is set.
The user attribute default only seeds the filter's initial value. Viewers can still change the filter unless its visibility is set to Disabled, in which case the resolved attribute value is locked in for that viewer. Values passed via URL parameters also take precedence over user attribute defaults, so deep links continue to work.
When multiple filters target dimensions from the same semantic view, you can mark them as faceted. Faceted filters scope each other's value lists — selecting a value in one filter narrows the options shown in the others, so viewers only see combinations that exist in the data.
For example, on a sales dashboard with a Country filter and a City filter, marking both as faceted means selecting United States in the Country filter limits the City filter to U.S. cities only.
Time granularity switchers let viewers change the granularity of time-based dimensions on the dashboard — for example, switching a revenue chart from daily to weekly or monthly. The widget targets a single time dimension and applies the chosen granularity to every chart that groups by that dimension.
In the dashboard builder, open the Add Controls menu in the toolbar and choose Time Granularity. The new switcher is added in an unconfigured state — open its settings to pick a semantic view and a time dimension.
By default, viewers can choose between day, week, month, quarter, and year. You can narrow this list in the widget's settings to only expose the granularities that make sense for the dashboard.
For time dimensions backed by a TIMESTAMP or DATETIME column, sub-day granularities (second, minute, hour) are also available. DATE-typed columns don't expose sub-day granularities, since they would bucket the entire day into a single point.
Custom granularities defined in the data model aren't offered in this list yet — the switcher exposes the built-in granularities only.
You can configure a default granularity that's applied when the dashboard loads. If no default is set, charts use the granularity that was saved on the underlying report — viewers can still switch granularities, but the dashboard opens with each chart at its original granularity.
A field switcher lets viewers change which dimension or measure the charts are built on — swapping a revenue chart's breakdown from Status to City, or its measure from Order count to Total revenue — without leaving the dashboard or opening the report.
Where a filter narrows the rows and a time granularity switcher rebuckets them, a field switcher replaces the member itself in the chart's query. One dashboard can then answer several questions that would otherwise need a chart each.
In the dashboard builder, open the Add Controls menu in the toolbar and choose Field Switcher, then click Configure Field Switcher to set it up.
A field switcher works on one member kind at a time — set Field Type to either Dimension or Measure. The rest of the settings follow from that choice:
| Setting | What it does |
|---|---|
| Field Type | Whether this control swaps a dimension or a measure. Switching the type resets the settings below it, since the two draw from different pools. |
| Dimension to Replace / Measure to Replace | The member the charts are currently built on — the one this control stands in for. |
| Alternatives | The members viewers may switch to. The replaced member is always offered as well, so a viewer can get back to the original view. |
Alternatives come from the control's own semantic view, and must be the same kind as the replaced member — a dimension switcher offers dimensions, a measure switcher offers measures.
The member a viewer starts on is set the same way a filter's static default is: by picking it in the control while you're in the dashboard builder. The selection is saved on the widget and applied to every viewer when the dashboard loads. If you never pick one, the dashboard opens on the replaced member.
Removing a member from Alternatives after it was serving as the default clears the default, so viewers can't start on a member the control no longer offers.
When a dimension switcher offers time dimensions, each of them can carry its own granularity, set under Default granularity per option.
This exists because a swap otherwise inherits whatever granularity the chart already had. A viewer moving from Created at to a Completed at that only makes sense monthly would get the replaced dimension's daily buckets, and the author would have no way to say otherwise.
Each time option is either pinned to a granularity or left at Inherit from the chart, which is the default and the behavior of every control configured before this setting existed. Non-time options don't have the setting, and a measure switcher has no granularities to speak of.
If the dashboard also has a time granularity switcher pointed at the swapped-in dimension, the viewer's own pick wins over the per-option granularity — a granularity a viewer actively chose outranks one the author set as a starting point. A granularity control nobody has touched does not.
Like filters and parent controls, a field switcher can start each viewer on their own member. Turn on User attribute default in the control's settings and pick a user attribute; when the dashboard loads, Cube reads that attribute for the current viewer and opens the control on the member it names.
This is how one dashboard opens on the breakdown each audience cares about — a Breakdown switcher opening on region for one team and channel for another, from a single published dashboard.
The attribute seeds the selection, exactly as the default option does, and loses to a pick the viewer has already made. A value that isn't among the Alternatives is ignored rather than forced: the attribute is set per user and the options are set per dashboard, so the two can drift apart without anyone editing either, and the safe reading of an unusable value is "no opinion" — the control falls back to the default option.
The swapped-in member is queried under the replaced member's output name, so everything the chart configured against that column keeps working across a switch — column formatting, sorting, pivots, and conditional formatting rules all survive, rather than resetting each time the viewer picks a different member.
Cube applies the switch in two places: to the SQL that runs, and to the query description the chart formats its results with. It applies the switch only if both take it — otherwise the chart would be labelled and formatted as one member while showing another's numbers, which nothing on screen would reveal.
When only one half can take it, the chart keeps rendering the member it was built on and shows a notice reading "The Field switcher could not be applied to this chart". The usual reason is a query Cube can't read back as semantic members — a hand-written one, or one built with a JOIN or UNION. The rest of the dashboard still switches.
A chart whose query doesn't use the replaced member at all is a different case: it is simply out of the control's scope, exactly as it would be for a filter, and shows no notice.
A chart with a period comparison is a narrower case: the comparison can't follow a member switch, so the chart applies the switch and drops the comparison, saying so in its own notice rather than silently showing a comparison that no longer matches the data.
<Note> A field switcher can't be a [parent control's](#parent) child, and a viewer's choice in one isn't carried in the [shared URL](#sharing-the-current-selection). Both are current limitations rather than deliberate design. </Note>A parent control is a dropdown of options you define. Picking one re-points a whole row of other controls at once — so a viewer makes a single choice instead of adjusting three or four filters by hand.
Unlike the other control types, a parent control targets no member and never touches a chart query directly. It applies values to the controls it drives — its children — and those children then apply themselves to charts exactly as if the viewer had operated each one. Filters and time granularity switchers can both be children; a field switcher cannot yet, and a parent control cannot be a child of another parent control.
For example, an Analysis parent with the options Retail, Wholesale and Promo can set a Channel filter, a Minimum order value filter, and a Date range filter to a different combination for each option. Viewers see one dropdown; you can hide the children if the individual values aren't worth showing.
In the dashboard builder, open the Add Controls menu in the toolbar and choose Parent, then click Configure Parent to set it up. The editor has two tabs — Options and Children.
<Info> Add the child controls to the dashboard *before* the parent control. The **Children** tab can only map controls that already exist, so a parent added to an empty dashboard has nothing to drive yet. </Info>On the Options tab, type a label and click Add for each entry you want in the dropdown. Options appear as chips — remove one with its close button. A parent control can hold up to 50 options.
Renaming an option later doesn't disturb the values you've mapped to it, so you can reword a label without redoing the mapping — but if the control has a user attribute default, that match is by label, so rename the attribute's values with it.
On the Children tab, pick a control from Child control, then give each of the parent's options a value for it. Each row renders that child's own control — a time granularity switcher's row shows its granularity picker, limited to the granularities that switcher allows; a filter's row shows that filter's operator and value inputs. So the values you can offer are exactly the ones a viewer could pick in the child itself.
Repeat for each control you want the parent to drive. Every option/child pair can be in one of three states:
| State | What happens when the viewer picks that option |
|---|---|
| A value | The child is set to that value. |
| Reset to default | The child is cleared back to its own default. For a filter that means no filtering on that dimension. Turn on the row's Reset to default switch. |
| Left empty | The child is left alone — it keeps whatever value the viewer already had. Use this deliberately when an option shouldn't have an opinion about a particular child. |
While the parent's settings are open, the children it drives are highlighted on the canvas, so you can see the scope of the mapping at a glance.
A control can be driven by only one parent control at a time. Mapping a child that another parent already drives moves it rather than sharing it — the editor warns you before you save, naming the parent that currently owns it.
Once a dashboard has at least one parent control, every filter and time granularity switcher on it shows a small indicator reporting how it's driven. Field switchers don't, since a parent can't drive one:
| Status | Meaning |
|---|---|
| Fully driven | Every option of the owning parent sets this control. |
| Partly driven | Only some of the owning parent's options set this control; the rest leave it alone. |
| Not driven | No parent control maps this one. |
Click the indicator to jump straight to the Children tab of the parent that owns that control, with it already selected. For a control nothing drives yet, the click opens the first parent control on the dashboard — topmost, then leftmost — so you can map it.
A parent control's default is set the same way a filter's static default is — by interacting with the control in the dashboard builder. The option you select is saved on the widget and applied to every viewer when the dashboard loads; there's no static default field in the parent's settings.
Picking in the builder also applies that option's values to the children, so their saved defaults line up with the parent's and a published dashboard opens in a consistent state.
If you never pick an option, the parent opens with nothing selected and the children use their own defaults. Deleting the option that was serving as the default clears it, and the parent goes back to opening on nothing.
The default above is one arrangement for everyone. To give each viewer their own, turn on User attribute default in the parent control's settings and pick a user attribute. When the dashboard loads, Cube reads that attribute for the current viewer and opens the control on the option it names — and drives the children with it, exactly as if the viewer had picked that option themselves.
This is how you ship one dashboard that opens differently per audience: a Reporting period parent whose options are Month and Quarter, opening on whichever one the viewer's reporting_period attribute says, with every filter and time granularity switcher behind it already set to match.
To configure it:
<Steps> <Step title="Open the parent control's settings"> In the dashboard builder, click **Configure Parent** on the control. </Step> <Step title="Enable User attribute default"> Below the **Options** and **Children** tabs — next to **Visibility** — turn on the **User attribute default** switch. </Step> <Step title="Pick the attribute"> Select the [user attribute][ref-user-attributes] to resolve. Only attributes defined in your account appear in the picker. </Step> </Steps>The attribute value is matched against the option labels, ignoring case and surrounding spaces — an attribute reading quarter selects the option labelled Quarter. Give the options the labels your attribute already uses, or adjust the attribute values to match.
| Attribute type | How it's applied |
|---|---|
| String, Number | Matched against the option labels as a single value. |
| String array, Number array | The first entry that names an option wins. A parent control is single-select, so the rest are ignored. |
If the value matches no option — or is empty, null, or unresolvable — the control falls back to the default option you picked, and the children keep the arrangement that goes with it.
Viewers can still switch to another option unless the control's visibility is set to Disabled, and their own pick outranks the attribute for the rest of the session. Values passed in the URL outrank both — but only what the sharer actually picked travels: a parent control has no parameter of its own, and an untouched, attribute-resolved one puts nothing in the link, so the recipient still opens on their own attribute. When the sharer did pick an option, the link carries that option's children's values and the recipient opens on those.
On a published dashboard, the values a viewer picks in the controls are reflected in the URL, so the view they are looking at is bookmarkable and shareable. Copy the address bar, send it on, and the recipient opens the dashboard with the same filters and granularities applied.
Each control type has its own parameter:
| Control | Parameter | Example |
|---|---|---|
| Filter | f_<semantic_view>.<dimension>=<JSON> | f_orders.status={"value":"shipped"} |
| Time granularity switcher | tg_<semantic_view>.<dimension>=<granularity> | tg_orders.created_at=week |
The semantic view and dimension are the internal names configured on the control — not the display titles you see in the picker. A view shown as Orders is usually orders in the parameter. Granularities are lowercase and must be one of the switcher's allowed granularities — day, week, month, quarter, year, plus second, minute, and hour for time dimensions that expose them.
You can also write these parameters by hand to open a dashboard in a particular state — see Pre-set dashboard filters and granularities via URL for the embedded case, which uses the same format.
What does and doesn't travel in the link:
When a dashboard opens with these parameters, they are applied on top of whatever defaults the controls carry. A parameter is ignored when nothing on the dashboard can honor it — there is no matching control for that dimension, or the requested granularity isn't in the switcher's allowed granularities.
Each control has a Visibility setting that determines how it appears on the published dashboard. The setting applies to all four control types.
| Visibility | Behavior on the published dashboard |
|---|---|
| Visible (default) | Shown on the dashboard and viewers can change its value. |
| Hidden | Not shown to viewers, but the control's value is still applied to the charts it targets. Use this to scope a dashboard with a fixed value — e.g., always filter to the current quarter — without exposing the control. Hiding the children of a parent control is the usual way to present one dropdown instead of the row of controls behind it. |
| Disabled | Shown on the dashboard so viewers can see the active value, but they cannot change it. |
Set the visibility from the Visibility dropdown when editing the control. Hidden controls remain visible in the dashboard builder so editors can reconfigure them, but disappear from the published view.
This section applies to filters, time granularity switchers and field switchers. A parent control has no member of its own and never applies to a chart itself, so it doesn't appear in any chart's Controls mapping — it acts only through the children it drives, and it's those children that show up here.
When a control is added to a dashboard, it's automatically wired up to every chart whose query already uses the same member. Charts that don't reference that member are left alone, so a dashboard can mix scoped and unscoped views by default. Filters and time granularity switchers always target a dimension; a field switcher targets a dimension or a measure depending on its Field Type, and scopes on whichever it is set to. You can override this default per chart from its Controls mapping — disable the control for that chart, or remap it onto a different member.
If controls of a certain type are incompatible with a particular chart's query, the chart skips all controls of that type and renders the data without them. Each type is skipped independently — if filters fail but a time granularity switcher works, the chart shows the granularity-adjusted data without filtering, and vice versa. A field switcher that can't be applied says so on the chart itself rather than through the icons below.
The chart displays a warning icon to indicate the problem:
| Icon | Meaning |
|---|---|
| Crossed-out filter | Filters were skipped for this chart |
| Crossed-out clock | Time granularity override was skipped for this chart |
Hover over the icon for details. Click it to open the chart's Controls mapping and fix the issue — remap the control to a compatible dimension or disable it for this chart.
Each chart decides which controls apply to it through its Controls mapping. The mapping is resolved automatically in most cases and only needs manual attention when a control targets a member the chart doesn't have.
Open Controls mapping from a chart's settings menu to inspect or override the mapping for that chart. For each control on the dashboard you can:
Three states show up in the mapping sidebar:
| Status | What it means |
|---|---|
| Mapped automatically | The control's member exists on the chart's semantic view, so it's wired up without configuration. |
| Manually mapped | You (or an AI agent) picked a specific member for this chart. Reset restores the automatic mapping. |
| Can't map automatically | The control targets a member that doesn't exist on the chart's semantic view. The chart is unaffected by the control until you map it manually. |
Each control's picker offers only the members it can actually be resolved against, so a mapping you can stage is a mapping that will work:
| Control | What the picker offers |
|---|---|
| Filter | Dimensions on the chart's semantic view. |
| Time granularity switcher | Time-typed dimensions only — other types can't be resolved by the time granularity pipeline. |
| Field switcher set to Dimension | Dimensions. |
| Field switcher set to Measure | Measures, since the control replaces a measure. |
Filter and time granularity mappings are also configurable by AI agents when they build or edit a dashboard, so an agent can wire those controls across charts that use different semantic views without you needing to revisit each chart manually. Field switchers are outside what agents author, so their mappings are yours to set.