Build a Grouped Gallery in Power Apps with Custom Headers
Insert group headers between rows of a gallery to organize data into sections, similar to a calendar grouping events by date.
By default, a Power Apps gallery shows a continuous list of records. When you need to present related items under a bold heading—like “Sessions by day” or “Tasks by priority”—you must manually inject group headers into the data stream. This article walks through a reliable pattern that turns a flat gallery into a grouped, calendar‑style view using only raw Power Fx and a SharePoint list.
We’ll build a conference session schedule where each day appears as a header, followed by the sessions that belong to that day. The same technique works for any grouping field: status, category, department, etc.
Scenario: Conference Sessions by Date
Your conference app pulls data from a SharePoint list named ConferenceSessions with these columns:
| Column | Data type | Example |
|---|---|---|
| SessionDate | Date only | 2026-06-05 |
| SessionTime | Date & time | 6/5/2026 09:00 AM |
| Title | Text | "Building Copilot Agents" |
| Speaker | Text | "Aisha Chen" |
| Room | Text | "Room 301" |
The goal is to display a gallery that looks like this:
June 5, 2026 (group header) 09:00 AM – Building Copilot Agents – Aisha Chen – Room 301 10:30 AM – Power Automate for Beginners – Mark Torres June 6, 2026 (group header) 09:00 AM – Advanced Dataverse – Susan Park 11:00 AM – Canvas App Patterns – Raj Patel
We’ll create a collection that mixes group‑header rows (level 1) with data rows (level 2), then sort the collection so each header appears before its items.
Step-by-Step Implementation
1. Create the SharePoint List
Build a list named ConferenceSessions with the columns shown above. Populate it with a handful of sessions across two or three dates so you can test the grouping.
2. Build the Canvas App
- Open Power Apps Studio and create a blank phone app.
- Add a connection to your ConferenceSessions list.
- Insert a Vertical gallery and temporarily set its Items property to
'ConferenceSessions'to see the raw data. - Change the screen’s Fill to a light gray (e.g.,
RGBA(237, 237, 237, 1))—this color will become the background of the group headers.
3. Prepare the Supporting Collections
We’ll use a temporary button to write and test the Power Fx. Add a Button anywhere on the screen (you can hide it later or remove it when finished).
Set the button’s OnSelect to the following code block. The logic is explained in comments; the actual code is broken into separate ClearCollect calls for clarity.
// 1. Load all sessions and add a "Level" column (value 2 = data row)
ClearCollect(colAllSessions,
AddColumns(
ShowColumns('ConferenceSessions', "Title", "SessionDate", "SessionTime", "Speaker", "Room"),
"Level",
2
)
);
// 2. Extract unique session dates and mark them as group headers (Level 1)
ClearCollect(colUniqueDates,
AddColumns(
RenameColumns(
Distinct('ConferenceSessions', SessionDate),
"Value",
"SessionDate"
),
"Level",
1
)
);
// 3. Combine data rows and header rows into one collection
ClearCollect(colCombined,
colAllSessions,
colUniqueDates
);
// 4. Sort by date first, then by Level (so header comes before items), then by time for items
ClearCollect(colSorted,
Sort(
colCombined,
"SessionDate",
SortOrder.Ascending,
"Level",
SortOrder.Ascending,
"SessionTime",
SortOrder.Ascending
)
);
After clicking the button, inspect the collection colSorted in the Variables pane. You should see rows where Level = 1 (header) with only the SessionDate filled, and rows where Level = 2 (item) with all fields. Headers appear immediately before the items of that date.
4. Point the Gallery to the Sorted Collection
Change the gallery’s Items property to colSorted. The gallery will now contain both header and item rows. Because the column names differ slightly (some columns are blank for headers), the existing labels may show empty fields for header rows. That’s fine; we’ll style them differently next.
5. Differentiate Headers from Items
Inside the gallery template, add two Label controls (or containers) that will be conditionally visible based on the Level value.
- Header label: Show only when
ThisItem.Level = 1. Set its Text to something likeText(ThisItem.SessionDate, "dddd, mmmm dd, yyyy"). Make the text bold, larger, and apply the gray background color (inherited from the screen) to create a visual section break. - Item details: Show when
ThisItem.Level = 2. Use the usual labels for title, speaker, room, and time. The time label can useText(ThisItem.SessionTime, ShortTime).
Set the Visible property of the header label to ThisItem.Level = 1. For the item details, set their Visible property to ThisItem.Level = 2 (or combine them into a container with that condition). You may also want to hide the default separator line on header rows.
6. Remove the Temporary Button
Once the gallery works correctly, delete the temporary button. Move the data‑building logic to the screen’s OnVisible property or to the gallery’s OnSelect of a hidden button. Because collections only need to be built once per session, you can also use:
If(IsEmpty(colSorted),
ClearCollect(... /* all four steps above */ )
)
Place this in the screen’s OnVisible to avoid repeating the collection on every revisit.
Performance & Delegation Notes
- Distinct delegation: The
Distinctfunction is not delegable for SharePoint. When your list exceeds 500 items, the function may only evaluate the first 500 records, causing missing group headers. For larger lists, consider using a separate “Date” look‑up list or a Power Automate flow to pre‑compute dates. - ClearCollect and Sort: These functions operate on the client side after data is retrieved. Loading thousands of records may increase app startup time. Limit the data with a
Filterif possible (e.g., only future dates). - Alternate approach: If you need absolute delegation, create a second SharePoint list that holds the unique dates and use
LookUpin the gallery to display headers at a calculated row index. However, the collection method shown here is simpler for datasets under 2000 items.
Common Mistakes & Troubleshooting
| Mistake | Consequence | Fix |
|---|---|---|
Sorting by Level before SessionDate | Headers interleaved out of order | Verify the sort order in the last ClearCollect: date → level → time. |
| Header row showing blank fields | Gallery displays empty lines for header rows | Use conditional visibility to hide item‑only labels when Level = 1. |
Not renaming the Distinct output column | Column name “Value” causes mismatch | Use RenameColumns(…, "Value", "SessionDate"). |
| Forgetting to clear collections | Duplicate rows after screen revisit | Use ClearCollect (which clears and fills) instead of Collect. |
Final Recommendation
The collection + sort pattern gives you full control over grouping in any gallery without relying on an external component. For small to medium datasets (a few hundred rows) it is fast and easy to maintain. Combine it with a loading indicator if the data takes more than a second to prepare.
To elevate the experience further, consider storing the group logic in a named formula (if you are on an environment that supports it) or encapsulating it inside a Power App Component for reuse.
References
- Mathew Devaney’s original article: Group The Items In A Power Apps Gallery
- Microsoft Learn: Collect, ClearCollect functions (retrieve order of columns) – Collect in Power Apps
- Microsoft Learn: Distinct function with delegation considerations – Distinct in Power Apps
- Microsoft Learn: Gallery control inside Power Apps – Add a gallery
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.