---
title: Controls
description: Filter, time granularity switcher, field switcher, and parent widgets that let dashboard viewers change what's shown on the dashboard.
---

Controls are widgets that let dashboard viewers change what's shown without leaving the dashboard. The dashboard builder offers four control types:

- [Filter](#filter) — Narrow the data shown on the dashboard
- [Time granularity switcher](#time-granularity-switcher) — Change the granularity of time-based dimensions
- [Field switcher](#field-switcher) — Swap which dimension or measure the charts are built on
- [Parent](#parent) — Re-point several other controls at once from a single dropdown

The first three each target a member from your semantic model, and apply the viewer's choice to every [chart][ref-charts] 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

Filter widgets let viewers narrow down the data shown on the dashboard. In the [dashboard builder][ref-workbooks], 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.

### Operators by dimension type

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` |

### Single vs. multiple selection

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.

### Default values

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 default** — pick a value (or values) directly in the filter. Every viewer sees the same default.
- **User attribute default** — resolve the default from the viewer's [user attribute][ref-user-attributes] at load time, so each viewer sees their own personalized default. [Time granularity switchers](#time-granularity-user-attribute-default), [field switchers](#field-switcher-user-attribute-default) and [parent controls](#parent-user-attribute-default) support this too.

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.

#### User attribute default

Use the **User attribute default** toggle in the filter's edit sidebar to pre-fill a filter from the viewer's [user attribute][ref-user-attributes]. 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](#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.

### Faceted filters

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 switcher

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][ref-granularities] to every chart that groups by that dimension.

In the [dashboard builder][ref-workbooks], 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.

### Allowed granularities

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][ref-granularities] aren't offered in this list yet — the switcher exposes the built-in granularities only.

### Default granularity

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.

#### User attribute default {#time-granularity-user-attribute-default}

The default above is one granularity for everyone. To give each viewer their own, turn on **User attribute default** in the switcher's settings and pick a [user attribute][ref-user-attributes]. When the dashboard loads, Cube reads that attribute for the current viewer and opens the control on the granularity it names.

This is how one dashboard opens at the interval each audience works in — daily for the operations team, monthly for the executives who read the same charts — from a single published dashboard.

To configure it:

<Steps>
 <Step title="Open the switcher's settings">
   In the dashboard builder, open the widget's settings menu and choose **Edit Control**.
 </Step>
 <Step title="Enable User attribute default">
   Below **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 **granularity names** the switcher [allows](#allowed-granularities) — `day`, `week`, `month`, `quarter`, `year`, and `second`, `minute`, `hour` where the dimension exposes them — ignoring case and surrounding spaces, so an attribute reading `Week` resolves to `week`. The names are matched, not the labels the control displays, so one attribute works the same for viewers in every language.

| Attribute type | How it's applied |
|---|---|
| **String**, **Number** | Matched against the granularity names as a single value. |
| **String array**, **Number array** | The first entry that names an allowed granularity wins. The switcher is single-select, so the rest are ignored. |

A value that isn't one of the switcher's [allowed granularities](#allowed-granularities) — or is empty, `null`, or unresolvable — is ignored rather than forced, and the control falls back to the [default granularity](#default-granularity). Attributes are set per user and the allowed list per dashboard, so the two can drift apart without anyone editing either; the safe reading of an unusable value is "no opinion".

<Note>
The attribute is resolved for the viewer, not baked into the dashboard. Editing the attribute's value changes what that viewer opens on the next time the dashboard loads; it never rewrites the published dashboard, so the default granularity you set in the builder stays intact for everyone else.
</Note>

Viewers can still switch granularities unless the control's [visibility](#visibility) is set to **Disabled**, and their own pick outranks the attribute for the rest of the session. A granularity passed [in the URL](#sharing-the-current-selection) outranks both, so deep links continue to work. If a [parent control](#parent) drives this switcher and the option the viewer is on maps a granularity to it, that mapping decides the granularity — a mapping the author made for that arrangement is more specific than a per-viewer starting point. An option that [leaves the switcher empty](#children) has no opinion, so the attribute still seeds it; one set to **Reset to default** sends the switcher to the [default granularity](#default-granularity) saved on it rather than re-resolving the attribute, and leaves the switcher untouched when no default granularity was saved.

## Field switcher

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](#filter) narrows the rows and a [time granularity switcher](#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][ref-workbooks], open the **Add Controls** menu in the toolbar and choose **Field Switcher**, then click **Configure Field Switcher** to set it up.

### Choosing what it switches

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.

### Default option {#field-switcher-default-option}

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.

### Default granularity per option

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](#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.

### User attribute default {#field-switcher-user-attribute-default}

Like [filters](#user-attribute-default), [time granularity switchers](#time-granularity-user-attribute-default) and [parent controls](#parent-user-attribute-default), 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][ref-user-attributes]; 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](#field-switcher-default-option) does, and loses to a pick the viewer has already made. A member passed [in the URL](#sharing-the-current-selection) outranks both, so deep links keep working. If a [parent control](#parent) drives this switcher and the option the viewer is on maps a member to it, that mapping decides the member; an option that [leaves the switcher empty](#children) has no opinion, so the attribute still seeds it, and one set to **Reset to default** sends the switcher to its [default option](#field-switcher-default-option) rather than re-resolving the attribute. 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.

### What the swap preserves

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.

### When a chart can't take the switch {#when-a-chart-cant-take-the-switch}

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][ref-charts] 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.

## Parent

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, time granularity switchers and [field switchers](#field-switcher) can all be children; 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](#visibility) the children if the individual values aren't worth showing.

In the [dashboard builder][ref-workbooks], 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>

### Options

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](#parent-user-attribute-default), that match is by label, so rename the attribute's values with it.

### Children

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; a field switcher's row shows its member picker, limited to the members that switcher offers — its **Alternatives**, plus the replaced member. 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 put back to its own default. For a filter that means no filtering on that dimension; for a time granularity switcher, its [default granularity](#default-granularity); for a field switcher, its [default option](#field-switcher-default-option). 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.

### One parent per child

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.

### Mapping status on child controls

Once a dashboard has at least one parent control, every filter, time granularity switcher and [field switcher](#field-switcher) on it shows a small indicator reporting how it's driven:

| 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.

### Default option

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.

#### User attribute default {#parent-user-attribute-default}

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][ref-user-attributes]. 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 control 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.

<Warning>
Renaming an option leaves its child mappings intact, but the attribute match is by label — so a rename that moves a label away from the values your attribute holds silently stops it resolving, with no error. The control falls back to the option you picked as the default. Rename labels and attribute values together.
</Warning>

| 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](#default-option) you picked, and the children keep the arrangement that goes with it.

<Note>
The attribute is resolved for the viewer, not baked into the dashboard. Editing the attribute's value changes what that viewer opens on the next time the dashboard loads; it never rewrites the published dashboard, so the default you picked in the builder stays intact for everyone else.
</Note>

Viewers can still switch to another option unless the control's [visibility](#visibility) is set to **Disabled**, and their own pick outranks the attribute for the rest of the session. Values passed [in the URL](#sharing-the-current-selection) 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.

## Sharing the current selection

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, granularities and member choices applied.

Each control type has its own parameter:

| Control | Parameter | Example |
|---|---|---|
| [Filter](#filter) | `f_<semantic_view>.<dimension>=<JSON>` | `f_orders.status={"value":"shipped"}` |
| [Time granularity switcher](#time-granularity-switcher) | `tg_<semantic_view>.<dimension>=<granularity>` | `tg_orders.created_at=week` |
| [Field switcher](#field-switcher) | `ms_<semantic_view>.<replaced_member>=<selected_member>` | `ms_orders.status=users_city` |

The semantic view and member 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. The same goes for the member on the right-hand side of `ms_`: it is the internal name of the member to switch to, and it is a measure rather than a dimension when the switcher's **Field Type** is **Measure**. Granularities are lowercase and must be one of the switcher's [allowed granularities](#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][ref-embed-url-filters] for the embedded case, which uses the same format.

What does and doesn't travel in the link:

- **Only what the viewer chose.** Values that came from the control's own configuration — a static default, a [default granularity](#default-granularity) — are not written into the URL. Every viewer already gets those from the dashboard itself, and leaving them out means a link stays correct after the dashboard's defaults change.
- **Never a personalized default.** A value resolved from a [user attribute](#user-attribute-default) stays out of the link — whether it seeded a filter, a [time granularity switcher](#time-granularity-user-attribute-default) or a [field switcher](#field-switcher-user-attribute-default) directly, or reached one through a [parent control](#parent) opening on the viewer's own option. Sharing a dashboard never pins your attribute value onto the recipient; they see it through their own attributes.
- **Every control's pick, together.** Picking in several controls puts them all in the link, including when a [parent control](#parent) sets several children at once — filters, time granularity switchers and [field switchers](#field-switcher) alike. A parent control isn't serialized itself — the link carries the values its children ended up with, so the recipient sees the same data while the parent dropdown opens on whatever default it resolves for them, which may not be the option the sharer picked.
- **Written out on published dashboards only.** Reading these parameters works anywhere, including [embedded][ref-embed-url-filters] dashboards; it's the writing that is published-only. In the dashboard builder the URL is left to the editing session, so changing a control there doesn't rewrite it.

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 member, the requested granularity isn't in the switcher's [allowed granularities](#allowed-granularities), or the selected member is one the field switcher doesn't offer — its **Alternatives**, plus the replaced member.

## Visibility

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](#parent) 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.

## Interaction with charts

This section applies to filters, time granularity switchers and field switchers. A [parent control](#parent) has no member of its own and never applies to a chart itself, so it doesn't appear in any chart's [Controls mapping](#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][ref-charts] 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](#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](#controls-mapping) — disable the control for that chart, or remap it onto a different member.

### Incompatible controls

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](#field-switcher) that can't be applied says so [on the chart itself](#when-a-chart-cant-take-the-switch) 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](#controls-mapping) and fix the issue — remap the control to a compatible dimension or disable it for this chart.

### Controls mapping

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:

- **Toggle the control on or off** for the chart, even when a mapping exists
- **Pick a different member** from the chart's semantic view to remap the control to

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](#filter) | Dimensions on the chart's semantic view. |
| [Time granularity switcher](#time-granularity-switcher) | Time-typed dimensions only — other types can't be resolved by the time granularity pipeline. |
| [Field switcher](#field-switcher) set to **Dimension** | Dimensions. |
| [Field switcher](#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.

[ref-embed-url-filters]: /embedding/iframe/dashboards#pre-set-dashboard-filters-via-url

[ref-workbooks]: /docs/explore-analyze/workbooks
[ref-charts]: /docs/explore-analyze/dashboards/widgets/charts
[ref-granularities]: /docs/data-modeling/dimensions
[ref-user-attributes]: /admin/users-and-permissions/user-attributes
