Shape-Shifting Forms: Data-Driven UIs in Power Apps
Eliminate form sprawl. Build one canvas form that reconfigures itself based on a configuration table. Perfect for adaptable intake processes.
Every Power Apps developer eventually hits the wall: your business owner wants a single screen that morphs into different forms based on a selection. Instead of coding ten nearly-identical screens, you can build one form that drives its structure from data. This technique—which I call the Adaptive Form Pattern—relies on a gallery and a configuration table to render the right controls at the right time. We will build an IT access-request intake form that adjusts its fields on the fly.
The Core Idea: Configuration-Driven UI
The principle is straightforward. The Items property of a vertical gallery points to a FormDefinition table. Each row is one field and contains:
- A
Prompt(the label the user sees). - A
ControlType(Text, Number, Radio, Combo, Date). - An
Optionslist for choice-based controls.
Inside the gallery template, you stack the input controls. Each control’s Visible property checks the current row's ControlType. When the gallery renders, it only shows the control that matches the row's definition.
Step 1: Define Your Form Configuration
Let's build the configuration table. For simplicity, we will create it in the app’s OnStart using a collection. Later, you can migrate this to a SharePoint list so business owners can edit the form without opening Power Apps Studio.
ClearCollect(FormConfig,
{ Id: 1, Prompt: "Requester’s Full Name", Type: "Text", Options: Blank() },
{ Id: 2, Prompt: "Employee ID", Type: "Number", Options: Blank() },
{ Id: 3, Prompt: "Department", Type: "Combobox", Options: ["Sales", "Support", "Engineering", "Finance"] },
{ Id: 4, Prompt: "Access Level", Type: "Radio", Options: ["Read Only", "Edit", "Admin"] },
{ Id: 5, Prompt: "Access Expiry Date", Type: "Date", Options: Blank() }
)Step 2: Build the Adaptive Gallery
- Insert a Blank vertical gallery onto your screen.
- Set its Items property to
FormConfig. - Inside the template, add the following controls:
- A Label for the prompt.
- A Text input (rename to
txt_PrimaryInput). - A Radio button (rename to
rdo_Options). - A Combo box (rename to
cmb_Options). - A Date picker (rename to
dte_DatePick).
Align the controls so they stack directly on top of each other in the same cell. Because only one control will be visible per row, they share the physical space without overlapping visually.
Step 3: Wire Visibility and Formatting
The logic belongs in the Visible and Format properties.
Label – Display the prompt:
ThisItem.Prompt
Text Input – Show for Text and Number types:
ThisItem.Type = "Text" || ThisItem.Type = "Number"
Text Input – Switch keyboard to numeric for Number type:
If(ThisItem.Type = "Number", TextFormat.Number, TextFormat.Text)
Radio Button – Visible for Radio type, load choices:
// Visible ThisItem.Type = "Radio" // Items ThisItem.Options
Combo Box – Visible for Combobox type, load choices:
// Visible ThisItem.Type = "Combobox" // Items ThisItem.Options // DisplayFields / SearchFields ["Value"]
Date Picker – Visible for Date type:
ThisItem.Type = "Date"
Preview the app. The gallery should now show a different control type on each row.
Step 4: Capture and Submit the Data
When the user clicks Submit, we need to:
- Loop through the gallery items.
- Read the value from whichever control is visible.
- Store the responses in a collection.
- Persist the data to SharePoint or Dataverse.
A two-step approach avoids concurrency issues that can arise when you Patch inside a ForAll.
// Step 1: Collect all responses
Clear(colResponses);
ForAll(gal_AdaptiveForm.AllItems,
Collect(colResponses,
{
Question: ThisRecord.Prompt,
Answer: Switch(ThisRecord.Type,
"Text", txt_PrimaryInput.Text,
"Number", txt_PrimaryInput.Text,
"Radio", rdo_Options.Selected.Value,
"Combobox", cmb_Options.Selected.Value,
"Date", Text(dte_DatePick.SelectedDate, DateTimeFormat.ShortDate)
)
}
)
);
// Step 2: Create the header record
Set(varFormHeaderId,
Patch(AccessRequests, Defaults(AccessRequests),
{ Title: First(colResponses).Answer, SubmittedOn: Now() }
).ID
);
// Step 3: Create the detail records
ForAll(colResponses,
Patch(AccessRequestDetails, Defaults(AccessRequestDetails),
{
RequestId: varFormHeaderId,
QuestionText: ThisRecord.Question,
ResponseText: ThisRecord.Answer
}
)
);
// Step 4: Reset the form
Reset(gal_AdaptiveForm);In the example above, AccessRequests is the header table and AccessRequestDetails stores the individual question/answer pairs linked via a lookup. Adjust the table and column names to match your actual schema.
Common Mistakes & Troubleshooting
Combo Box Value Extraction
cmb_Options.Selected returns a record. Always use .Value (e.g., cmb_Options.Selected.Value) when your Items is a single-column table. If your source comes from a SharePoint choice column, the column name is usually .Title.
Stale Values After Reset
Calling Reset(gal_AdaptiveForm) re-renders the gallery but does not clear the values inside the controls. To force a clean slate, recreate the configuration collection after submit:
// After the Reset call ClearCollect(FormConfig, Table(...)); // recreate your definition
Delegation Risk
The AllItems property of a gallery is not delegable. For almost all form definitions (usually under 50 rows) this is a non-issue.
If your configuration table lives in SharePoint and grows beyond 500 rows, cache it in a local collection on OnStart. The gallery reads from the collection at full speed.
Overlapping Controls
Every control inside the gallery must have its Visible property explicitly set. Leaving a control at the default true causes it to overlap with the intended visible control.
Advanced: Taking the Pattern Further
Section Headers
Add a Section column to your FormConfig. If the section value changes between rows, show a label that announces the new section. This creates a multi-page feel inside a single gallery.
Conditional Questions
Add a DependsOn column. Before making a control visible, check the answer of a previous question. This turns the form into a genuine decision tree.
Reusable Component
Export the gallery as a Power Apps Component. Pass FormConfig as a custom input property. Now you have a portable adaptive form that you can drop into any app without recoding a single line.
Recommendation
The Adaptive Form Pattern is one of the highest-leverage techniques in intermediate Power Apps development. It transforms a static screen into a configurable engine. Start with a hard-coded collection to validate the logic, then move the configuration to a SharePoint list where your team can modify fields without ever opening Power Apps Studio.
References
- Original concept by Matthew Devaney: Power Apps Dynamic Forms – Generate Forms From Question List
- Microsoft Learn: Add a gallery
- Microsoft Learn: Create and update collections
Learn how small coding practices—like using descriptive names, flattening conditions, and simplifying logic—can make your apps easier to update and less error-prone.
Move past the gallery and discover the hidden patterns for validation, navigation, and smart submission handling in your data entry forms.
PowerShell unlocks admin capabilities that the Power Platform admin center simply doesn’t offer—from recovering deleted apps to blocking trial licenses. Here’s how to wield them safely.