Learn how to build smart, responsive dropdown controls in Power Apps that filter based on each other's selections. This hands-on lesson walks you through cascading dropdowns, Combo Box configuration, and real-world data filtering patterns that eliminate bad data at the source.

Picture this: you're building a service request form for your company's IT helpdesk. A technician opens the app, selects "Hardware" as the problem category, and expects the next dropdown to show only hardware-related subcategories — not a chaotic list mixing software tickets, network issues, and HR requests. Instead, every time the first dropdown changes, the second one stays stubbornly populated with everything. Users start picking the wrong subcategory. Data gets dirty. Your manager asks why the form is "so confusing."
This is the cascading dropdown problem, and it's one of the first real hurdles that trips up new Power Apps builders. The good news is that Power Apps has two controls — the Dropdown and the Combo Box (which handles lookup-style selection) — that are extraordinarily powerful once you understand how to wire them to filtered data sources. By the end of this lesson, you'll know how to build dropdowns that respond to each other, filter records from real tables, and present clean, context-aware choices to your users.
What you'll learn:
Items propertyFilter() function to narrow down choices based on related dataBefore diving in, you should be comfortable with the basics of canvas app creation. If you haven't already, work through Build Your First Canvas App in Power Apps to make sure you can add controls and connect a data source. You should also have a basic grasp of how tables and records work in Power Apps — if terms like "column" and "record" feel fuzzy, a quick read of Power Apps Data Sources Explained: Tables, Records, and Collections for Absolute Beginners will give you solid footing.
Before you write a single formula, it's worth knowing why Power Apps gives you several similar-looking controls and what each one is actually designed for.
A Dropdown is the classic single-select control — it collapses to show one selected item and expands when clicked to reveal a list. It is the right tool when:
The Dropdown exposes a key property: Dropdown1.Selected, which returns the entire selected record, and Dropdown1.Selected.Value (or whatever column you're displaying), which gives you just the text.
A Combo Box is similar to a Dropdown but adds a search box and supports multi-select. It's the better choice when:
The Combo Box lets you separately define which column displays as the label (DisplayFields) and which column is the actual value (SearchFields). This distinction matters when your data source has something like a CustomerID column and a CustomerName column.
A ListBox is always expanded (never collapses) and supports multi-select natively. It's best for short, always-visible option sets where you want users to see all choices at once — think filter panels.
Note: For the rest of this lesson, we'll focus primarily on Dropdown and Combo Box since these are the most common in production apps. Everything you learn about filtering and cascading applies equally to ListBox.
Let's start with the fundamentals before we build cascades. Suppose you have a SharePoint list called ServiceCategories with a column called CategoryName. You've connected your app to SharePoint and the data source is available.
To populate a Dropdown:
Items property (it's selected by default for a new Dropdown)ServiceCategories
Power Apps will now show all records from the table. But you'll also need to tell the Dropdown which column to display. Look for the DisplayField property in the properties panel on the right side — set it to CategoryName.
Alternatively, you can use ShowColumns() in the Items formula to be explicit:
ShowColumns(ServiceCategories, "CategoryName")
Tip: Using
ShowColumns()is a good habit. It limits the data sent from the server to only what the control needs, which can meaningfully improve load times — especially important with large SharePoint lists or Dataverse tables.
Now your Dropdown is live. When a user picks "Hardware" from the list, DropdownCategory.Selected.CategoryName holds the string "Hardware".
The Filter() function is the engine that powers cascading selections. It scans a table and returns only the rows that match a condition you specify. The syntax is:
Filter(TableName, Condition)
For example, to get only service subcategories that belong to the "Hardware" category:
Filter(ServiceSubcategories, Category = "Hardware")
But here's where it gets interesting: instead of hard-coding "Hardware", you reference the current selection of your first Dropdown:
Filter(ServiceSubcategories, Category = DropdownCategory.Selected.CategoryName)
Now, every time the user changes DropdownCategory, the Filter() formula re-evaluates automatically. Power Apps is a reactive environment — formulas recalculate whenever their inputs change. You don't need event handlers or button clicks. The second Dropdown just stays current.
Key insight: This reactivity is what makes cascading dropdowns feel almost magical in Power Apps. There's no code to "trigger" the refresh. The moment
DropdownCategory.Selectedchanges, any formula that references it — including theItemsproperty of your second Dropdown — recalculates instantly.
Let's build this step by step with a realistic scenario. You're building an IT service request app. Your data lives in two SharePoint lists:
ServiceCategories (columns: ID, CategoryName)
ServiceSubcategories (columns: ID, SubcategoryName, ParentCategory)
DropdownCategory (select it, then change its name in the top-left name box)Items property to:ServiceCategories
DisplayField to CategoryNameDropdownSubcategoryItems property to:Filter(ServiceSubcategories, ParentCategory = DropdownCategory.Selected.CategoryName)
DisplayField to SubcategoryNameThat's the core cascade. Test it in preview mode (press the play button in the top-right): select "Hardware" in the first Dropdown and watch the second immediately narrow to only hardware subcategories.
Here's a subtle but important detail. Suppose a user selects "Hardware" and then picks "Laptop Repair" in the second Dropdown. Then they change their mind and switch the first Dropdown to "Software." The second Dropdown's list updates correctly — but the selected value might still show "Laptop Repair" until the user explicitly clicks something new. That's confusing and could lead to bad data being submitted.
To fix this, use the Reset() function on the first Dropdown's OnChange property:
Select DropdownCategory, then set its OnChange property to:
Reset(DropdownSubcategory)
Now whenever the first Dropdown changes, the second automatically clears its selection and resets to the top of its filtered list.
Warning:
Reset()only works on controls that have aResetfunction available (Dropdowns, Combo Boxes, Text Inputs, etc.). It does not reset variables or collections — just the control's own local state. If you're storing selections in variables, you'll need to clear those separately in the sameOnChangeformula.
Let's push further. A common real-world pattern is a three-level geographic hierarchy. Your data might look like this in three Dataverse tables:
Countries: CountryID, CountryName
States: StateID, StateName, CountryID
Cities: CityID, CityName, StateID
Notice that States links to Countries via CountryID, and Cities links to States via StateID. This is a foreign key relationship — one table's row references the ID of a row in another table.
Add DropdownCountry with:
Items: Countries
DisplayField: CountryName
Add DropdownState with:
Items: Filter(States, CountryID = DropdownCountry.Selected.CountryID)
DisplayField: StateName
Set DropdownCountry.OnChange:
Reset(DropdownState); Reset(DropdownCity)
Add DropdownCity with:
Items: Filter(Cities, StateID = DropdownState.Selected.StateID)
DisplayField: CityName
Set DropdownState.OnChange:
Reset(DropdownCity)
Notice how DropdownCountry.OnChange resets both downstream controls — because changing the country should clear both the state and the city, not just the state.
Tip: When you have three or more levels in a cascade, always reset all downstream controls from higher-level
OnChangeproperties. A user who changes Country and doesn't see City clear feels like the app has a bug, even if the underlying data is technically correct.
Sometimes your "dropdown" needs to behave more like a search field — think selecting a customer from a list of thousands. That's where Combo Box shines.
Add a Combo Box control and configure it like this:
Items to your Customers table (or a filtered version)DisplayFields to ["CustomerName"] — note the array syntax with square bracketsSearchFields to ["CustomerName", "CustomerEmail"] — users can search by either columnSelectMultiple as false unless you genuinely need multi-selectTo read the selected value from a Combo Box:
ComboBoxCustomer.Selected.CustomerID
Or if multi-select is on:
ComboBoxTags.SelectedItems // returns a table of selected records
The Combo Box also works beautifully in cascades. For example, a filtered Combo Box for contacts belonging to the selected customer:
Items: Filter(Contacts, CustomerID = ComboBoxCustomer.Selected.CustomerID)
Key insight: With Combo Box, Power Apps sends the search term to the data source (when delegation is supported) so it filters server-side. This makes it practical for tables with tens of thousands of rows — something a plain Dropdown can't handle gracefully. For more on why this matters, see Canvas App Delegation Deep Dive.
Now that you've built cascading selections, you need to actually do something with the chosen values — typically submit them as part of a form. Here's how selected values flow into other formula contexts.
Patch(
ServiceRequests,
Defaults(ServiceRequests),
{
Title: TextInputTitle.Text,
Category: DropdownCategory.Selected.CategoryName,
Subcategory: DropdownSubcategory.Selected.SubcategoryName,
RequestedBy: User().Email
}
)
Filter(
KnowledgeBase,
Category = DropdownCategory.Selected.CategoryName
)
If(
IsBlank(DropdownSubcategory.Selected.SubcategoryName),
Notify("Please select a subcategory before submitting.", NotificationType.Warning)
)
For deeper coverage of Patch(), Filter(), and related formulas, Master Power Apps Formulas: Navigate, Filter, Lookup, and Patch for Professional Apps is an excellent follow-on read.
Cause: The column name in your Filter() condition doesn't exactly match the column name in your data source. Power Apps column names are case-sensitive and can differ from how they appear in SharePoint's display.
Fix: In the formula bar, after typing Filter(ServiceSubcategories,, press the dot key and let IntelliSense show you the actual column names available. Use exactly those names.
Cause: Some data sources (especially SharePoint) can't delegate Filter() operations on certain column types. Non-delegable filters run client-side on the first 500 (or 2000) records, silently ignoring the rest.
Fix: This is a nuanced topic, but the short version is: use Dataverse instead of SharePoint for lookup tables when possible, or restructure your filter to use delegable column types. The Power Apps Performance Optimization article explains delegation limits in detail.
Cause: OnChange only fires when a user interacts with the control. It doesn't fire when the app initializes, so any setup logic in OnChange is skipped on first load.
Fix: Put initialization logic in the Screen's OnVisible property instead, or use the control's Default property to set initial values declaratively.
Cause: The Selected property of a Combo Box (singular) returns the first selected item. If SelectMultiple is true, users might not realize they need SelectedItems instead.
Fix: For single-select Combo Boxes, use .Selected.ColumnName. For multi-select, iterate over .SelectedItems using ForAll() or Concat().
Cause: When loading an existing record for editing, your OnChange resets clear the pre-populated downstream selections.
Fix: Use a context variable flag — like UpdateContext({IsLoading: true}) — and wrap your Reset() calls in an If(Not(IsLoading), Reset(...)) so they only fire during user interaction, not during data load. Power Apps Variables Explained covers context variables thoroughly.
Warning: When building edit forms with cascading dropdowns, test the pre-population scenario explicitly. It's one of the most common sources of bugs reported in production Power Apps. Build it, fill in a record, navigate away, come back, and verify everything loads correctly before shipping.
Build a three-screen mini-app that demonstrates a cascading Region → Department → Role selection, simulating an org chart lookup tool.
Your data (create as static collections in App.OnStart):
ClearCollect(
colRegions,
{RegionID: 1, RegionName: "North America"},
{RegionID: 2, RegionName: "Europe"},
{RegionID: 3, RegionName: "Asia Pacific"}
);
ClearCollect(
colDepartments,
{DeptID: 1, DeptName: "Engineering", RegionID: 1},
{DeptID: 2, DeptName: "Sales", RegionID: 1},
{DeptID: 3, DeptName: "Engineering", RegionID: 2},
{DeptID: 4, DeptName: "Finance", RegionID: 2},
{DeptID: 5, DeptName: "Operations", RegionID: 3}
);
ClearCollect(
colRoles,
{RoleID: 1, RoleName: "Senior Engineer", DeptID: 1},
{RoleID: 2, RoleName: "Staff Engineer", DeptID: 1},
{RoleID: 3, RoleName: "Account Executive", DeptID: 2},
{RoleID: 4, RoleName: "Sales Manager", DeptID: 2},
{RoleID: 5, RoleName: "Solutions Architect", DeptID: 3},
{RoleID: 6, RoleName: "Financial Analyst", DeptID: 4},
{RoleID: 7, RoleName: "Ops Lead", DeptID: 5}
)
Your task:
ddRegion, ddDepartment, ddRoleddRegion.Items to colRegions, display RegionNameddDepartment.Items to Filter(colDepartments, RegionID = ddRegion.Selected.RegionID), display DeptNameddRole.Items to Filter(colRoles, DeptID = ddDepartment.Selected.DeptID), display RoleNameddRegion.OnChange to reset both ddDepartment and ddRoleddDepartment.OnChange to reset ddRole"Selected: " & ddRegion.Selected.RegionName & " / " & ddDepartment.Selected.DeptName & " / " & ddRole.Selected.RoleNameStretch goal: Add a Combo Box to replace ddDepartment, with SearchFields set to ["DeptName"], so users can type to narrow the list. Observe how the selection behavior changes.
Tip: Using in-memory collections (
ClearCollect) is a fantastic way to prototype cascading controls before you connect real data sources. You get instant feedback without worrying about permissions or network latency. Once the UX feels right, swap the collection references for real table references.
You've covered a lot of ground. Here's what you can now do:
Items property and ShowColumns() for efficiencyFilter() with references to upstream control selectionsReset() in OnChange properties to prevent stale selectionsPatch(), Filter(), and validation formulasThe cascading pattern you've built here is a foundational UI pattern that appears in almost every serious business app — purchase order forms, HR onboarding tools, project trackers, service desks. Master it and you've mastered one of the most important interaction patterns in the Power Apps toolkit.
Where to go next: