Teams UI Toolkit for Makers: an introduction

As app makers, citizen developers, or low-code developers (pick your poison), building applications in the Power Platform, we know that canvas apps are the way to go if we want to have full control over the user interface. Then why do the bulk of canvas apps look alike? When you’ve built a canvas app, you can recognize most canvas apps from a mile away, because even though we have full control over the design, we often neglect this in favor of functionality.

When you’re building standalone canvas apps, you might get away with this. But when you’re starting to build applications for Microsoft Teams, a typical canvas app just doesn’t match with the clean and shiny Microsoft Teams interface.

Why care about design?

1. Increase adoption

A well-designed application is usually more intuitive than one lacking in design, intuitive applications are easier to use and therefore people will be more inclined to actually use them. Ultimately, we are building applications for people to use, and building applications that are easier to use will help reach that goal. Therefore, design is something we should care about and not only in the last 5% of development when we do small improvements.

2. Increase security

A lot of security efforts these days focus on raising awareness in people that “when things don’t look or feel right, they probably aren’t”. This goes for emails, text messages or calls they get, but just as well for applications that they use. If people are used to apps in Microsoft Teams all looking very similar or at least professional, they should have doubts about the odd one out that does not look similar at all. We can support the security efforts done in other areas by making sure that applications follow the same principles: make it fit in so that people don’t get an odd feeling when using it.

3. Make people happy

There’s no denying that we, as humans, like pretty things. Applications are no exception to that. If I can choose between two apps with the exact same functionality, where one is sleek and pretty, and the other is bulky and ugly, I’ll go for the pretty one. When people are happy when using an application, and design can help this feeling, they will be using it more, which in turn increases adoption again.

Microsoft Teams UI Toolkit

Now that you’re convinced (hopefully) that design is something to think about, let’s look at how you can make that happen for applications built for Microsoft Teams.

After duplication, you will see the following screen (or something similar):

In the navigation pane on the left, you will see a couple of different sections in the toolkit. These sections contain different types of information, and depending on what you are looking for, the information can be found in different sections. The sections can be described as follows:

  • General information: The first section contains general information about the toolkit, how to use it and where you can find related resources
  • Design system: This section contains high-level information about the design principles that should be used when developing an application for Microsoft Teams. You can find here information about the typical layout, spacing, color scheme, icons and fonts.
  • App capabilities: Here the general structure of an app is described depending on where in Teams it will be used; as a tab, a personal app or a bot for example. When looking at a Power App, this is taken care of by the default integration between Power Apps and Teams, and you can only influence what goes on in the content part of the app.
  • UI Components: In this section most of the basic UI components that can be used in an app are described in detail. If you are looking for specific details on what a button should look like, how to create a text input field, etc.; this is where you will find that information. Most likely this will be the most used section in the toolkit when building a Power Apps canvas app.
  • UI Templates: Finally, also a very useful section, in UI templates you will find several common “page types” or “control groups” that can be added into an application, e.g. a list of information, a form to be completed, and filters.

Using the Toolkit for canvas app development

The sections I have used the most for canvas app development are the last two. I usually take the approach of searching for a template that is the closest match to what it is I’m building, often combining different templates. This provides me with a general sense of which direction I’m going in. To define the specific properties of the controls on the screen, I go into the UI Components section and figure out the specific sizing, colors and states. I then apply these specifications (as best as possible) to the controls that I’m working with.

If you want to take this approach, it will take quite some time in the beginning to figure out the toolkit and find out which control configuration works best in canvas apps. After configuring a couple of controls, it becomes easier as you can simply copy them and change whatever is different. E.g., after you have configured one spotlight button and one normal button, you can simply copy these, change the label, display conditions and action and you’re good to go.

In following blog posts, I will showcase specific controls and how you can configure them so that they follow the Teams UI Toolkit guidelines. When these are published, they will be added as links below.

Matching the logged in user in a canvas app with a person column in SharePoint

Recently, I came across an interesting issue using people columns in a SharePoint list. We were working with a list in which multiple roles had been identified (reviewer, approver, etc.). Depending on the role a certain person had for a specific item, they should be able to take different actions in the canvas app built on top of that list. For example: approve an item if they are listed as the approver.

We tried to achieve this by checking that the logged in user’s email corresponds to the email of the person for that role. In most cases, this worked. However, in some cases, a user that is listed as an approver for an item did not see the approve/reject option. After some debugging, we figured out this was due to the fact that there was a mismatch between the result of the User().Email function in canvas apps, which returns the email of the logged in user, and the Approver.Email result, which is the email of the person in the Approver column.

The problem

To illustrate this problem, and the solution, I built a simple Holiday approval canvas app with a similar setup to the client application. In the below screenshots, you can see the logged-in user’s email address in the top right corner of the application, below their display name. One or more of the items in the list are assigned to each of the users. If the logged in user is the approver, they should have the Approve/Reject option available in the list, which is indicated with the canvas apps “DockCheckIcon” icon.

The first user, Hermione, does not give any issues. The email address of the logged-in user matches that of the approver in the SharePoint list, so the icon is visible. For the second user, Harry, the logged-in user’s email is listed as However, in the list it is, the primary alias that was defined for the user. Since these do not match, the icon is not visible. Finally, for the third user, Ron, only the capitalization between the two email addresses differs, giving the same result: the icon is not visible.

The root cause here is that we are comparing different things: the result of the User().Email function and Approver.Email property in the SharePoint list is not based on the same thing. I suspect User().Email actually provides the UPN (User Principal Name) of the user, whereas the Approver.Email property is the primary email. This is not necessarily constant, and can change for multiple reasons. Therefore, this is not a valid check to make.

The solution

Instead of comparing two different things, we should compare the UPN for both the logged-in user and the approver in the SharePoint list.

Let’s first get the UPN for the logged-in user. Since I am only assuming that the User().Email function returns the UPN, but I’m not sure about this (and this could potentially change in the future), I will not user this for the check. Instead, I will create a global variable for the UPN in the OnStart of the app and use the Office365Users connector and the available MyProfileV2() function to return the profile of the user currently logged in to the app. The profile contains a UserPrincipalName property, which is what we need.

The OnStart of the app is as follows:


For the approvers, we will need a different function, since we don’t need the logged in user’s profile, but the profile of the user specified in the approver column for each item in the list. In this case, I’m using the UserProfileV2() function.

⚠ Make sure to use V2 for this one. The UserProfile() function without V2 will not work with the email address, only with the UPN (which we don’t have, we are looking for it).

To make the icon visible only when there is a match, set the Visible property of the icon to

Office365Users.UserProfileV2(ThisItem.Approver.Email).userPrincipalName = varLoggedInUserUPN

If we now go back to the application for our 3 users, the approve icon will be visible when relevant for them.

For Hermione, the result is exactly the same. For Harry and Ron, it now looks different.

A closing note

This approach is not ideal, especially when working with larger datasets.

Since every item in the gallery items causes a call to the Office 365 Users connector to get the user profile, this may cause some delay in loading the screen and specifically the approve icon.

An alternative to avoid this call, could be using the Claims property that you can get from the Approver column properties (and trimming the prefix). In my tests, this seemed to be the user principal name (in lowercase), but I could not immediately find any confirmation for this. For this reason, and the fact that at the customer the dataset was rather small too, I have not used this approach. If you would be taking this approach however, make sure to decapitalize the UPN for the logged-in user too, otherwise there might be a mismatch still.

#LetsGetPersonal: Paralyzing pressure

After a hiatus of almost 6 months (not that I was super consistent in posting before, but still) I want to share the main reason why I was not blogging. I also want to share some tips (to my future self and possibly others) to prevent this from happening again.

What happened?

Sometimes, I take on too much work, and I don’t even realize that I’m doing this, while I’m doing it. It’s only after a while, when tasks or commitments become clearer, that I understand the impact this has on me, and with community commitments specifically my spare time. At this point, it’s very difficult to go back on promises made. Especially when you really, really, really want to do the thing you’ve committed to. What happens in my mind then, is that I feel a huge pressure to perform/deliver/show up/etc. This “pressure” can become overwhelming, and often I don’t even realize this is happening until it’s too late.

What then happens is one of two things:

  • I break down crying in public, probably in front of my manager (this has happened in the past and their reaction can make or break your professional relationship) – this is often the case when it’s work commitments that are building up
  • I am completely paralyzed mentally and every action takes such a huge amount of (mental) energy that nothing much happens anymore for any of my commitments apart from what absolutely needs to happen – this is usually for non-work commitments

The first one is pretty obvious, but it can take a while for the second one to become apparent. I can personally identify this is happening when

  • Tasks keep getting postponed
  • I put things on the calendar yet always find an excuse to do something else instead
  • I don’t do anything that does not have someone waiting for my output (e.g. blogging)
  • I often say (or think) “I didn’t have time for that”
  • I go to bed at night thinking “tomorrow I will do better” but tomorrow ends up being more of the same

Why this is a problem

Obviously, I’m not getting anything done this way. Which, if you decide to do that, is fine – there is nothing wrong with taking a break. The problem is that this happens unconsciously, which causes a vicious cycle:

  • I feel overwhelmed by the pressure (real or self-imposed)
  • I don’t get anything done
  • I feel guilty for not getting anything done
  • I blame myself for procrastinating/not making time/etc.
  • This causes more negative feelings which increases the stress I put myself under
  • I feel even more overwhelmed
  • Etc.

In my experience, feelings of guilt and blame don’t result in positive change. Instead, these are catalysts for negative feelings, which I don’t believe can have positive effects.

While this is happening, this is often not visible to others as it is an internal struggle. And for me, this is very difficult to talk about as this feels like I failed.

How to move forward?

Simply understanding and explaining what happens is not enough, this is not a solution. So I want to share how I am moving past the feelings of pressure that are paralyzing my, so that they can help you and future me if this happens.

1. Take a break

Instead of trying to do all the things on your list, or some of them, do nothing. And decide to do nothing for a couple of days. The different with doing nothing because you’re overwhelmed is that this time, it’s a decision. You take a break, a holiday, time off, however you want to call it, you don’t do anything about your tasks, and you decide not to feel guilty about it. This breaks the cycle and will lower your stress levels, allowing you to come back to your task list afterwards with less pressure.

2. Start small

When you come back to it, don’t immediately tackle the big things. Instead, go for some quick wins. Things that don’t take more than a couple of minutes or an hour tops. If need be, divide the tasks into smaller chunks and spread it over several days. It might take longer to get back into it the next day, but you will achieve even less by trying to tackle too much at once and ending back up to getting nothing done.

3. Communicate

If you feel comfortable, talk to people waiting on your input or feedback about the fact that you’re overwhelmed and that it will take some more time to get back to them. Everyone is human and most likely knows what this feels like, so they might be more understanding than you expect them to be. This one is very difficult for me, but when I do it, I’m always pleasantly surprised.

4. Slowly grow what you’re doing

Don’t try to go too fast. Gradually grow the size of your daily or weekly to do list to the level you feel comfortable with. Remember this can differ from day to day or week to week! Be realistic about what you can and want to do in any given period and try not to put too much pressure on yourself.

5. Remove guilt and blame from your vocabulary

Guilt and (self-)blame are negative emotions, which don’t create positive outcomes. When you find yourself overwhelmed and perhaps paralyzed again, don’t blame yourself, instead accept that not every day can be a success and forgive yourself. Be kind, to yourself as well as others. Positive emotions will lead to positive outcomes.

In conclusion

Life and work can be overwhelming. I hope that the behaviours, identifiers and especially steps to take can help you if you also experience this.

What has helped me unfreeze the last time has been taking a 3-week vacation from both work and community, starting small and releasing feelings of guilt over doing less for a time. Especially the last one is a game-changer! Good luck, and remember that life is a marathon, not a sprint.

You got this! 💜

Canvas app UI element: tag box & list

I love opportunities to create “new” UI elements for a canvas app. Recently, I came up with the idea of creating a list of text values of variable size with the ability to easily remove items from the list. This could be useful when you want to add tags in a record or create some related records to a main record without filling in all fields immediately. You could also use this to have a variable amount of filters that you want to apply to a data source.

Since the concept I had in mind reminded me of when you filter items in a webshop based on tags, I called it a “tag box & list” component.

Desired behavior

The behavior that I want to achieve is relatively simple. In a text input control, I want to type my input and when submitting, it should be added to a list below the text box. I don’t want duplicate values in the list and I want to be able to easily remove items from the list.

Since I’m thinking about UI, I want this to look good as well.


To build this, we need a couple of controls:

  • Text input
  • 2 buttons
  • Gallery, with inside
    • Label
    • Button
    • “Cancel” icon

The button inside the gallery will just be used for background of the item, so make sure it is at the bottom of the control hierarchy inside the gallery. In the below screenshots you can see the controls (I have renamed them to a descriptive name already).

Screenshot of the Power Apps control hierarchy indicating where the background button is in the tree.

Organize the controls as in the below screenshot (or a variation on it that best fits your application. Add the text “Add” to one of the buttons and “Clear” to the other. Of course you can style the controls according to your color scheme. I have made the “Clear” button gray so there is a distinction with the primary button to “Add” an item into the list below.

Screenshot of the organized controls in the canvas app

Basic logic

💡 In the function code, make sure to replace control and collection names with the names you are using.

o achieve the behavior described above, we’ll be working with a collection that is visualized inside the gallery. Items will be added to the collection using the text box (and “Add button”). To remove an item from the collection, the user presses the cancel icon inside the gallery, and the “Clear” button can be used to clear the collection with one click.

First thing to do is creating the collection by adding items into it. When a user presses the “Add” button we want to add whatever text is in the textbox to the collection. So, in the OnSelect property of the “Add” button, add the following code:


Clearing the collection is done by adding another piece of code into the OnSelect property of the “Clear” button.


To remove one item from the collection, add the following code into the “Cancel” icon’s OnSelect.


Now we have defined the collection, and we can visualize it inside the gallery. Add the collection, in my case colText, in the Items property of the gallery. Next, set the Text property of the label inside the gallery to:


You can now already test the tag box, and the basic functionality is complete: you can add tags into the list, remove one item from the list or clear the list completely.

The cherry on top

Now, there is some additional logic or functionality that I want to add.

  1. The text box should automatically clear after adding a value into the list
  2. Duplicate values should not be allowed
  3. The “Add” button should only be active when the textbox is not empty
1. Automatically clearing the textbox

To automatically clear the textbox, we’re going to introduce a local variable that will be used as the Reset property of the textbox control.

In the “Add” button’s OnSelect property, add two extra lines to your function so it becomes the following:

UpdateContext({locClearTextInput: true});
UpdateContext({locClearTextInput: false})

And set the Reset property of the textbox to


This ensures that the textbox will reset after the item is added into the collection.

2. Don’t allow duplicate values

When a user tries to add a duplicate value into the list, I want to display a warning and not add the item into the list. I don’t want to clear the textbox in this case, since it might be that they want two very similar items in their list.

To get this behavior, we will add onto the code we already have in the OnSelect property of the “Add” button – it’s really where all the magic happens. 😉 The complete function will be:

    txtTagToAdd.Text in colText,
        "The item is already in the list, please try again with a different value.",
    UpdateContext({locClearTextInput: true});
    UpdateContext({locClearTextInput: false})

This checks to see if the text that is currently in the textbox is already in the list. If this is the case, a warning is displayed. Otherwise, the item is added and the textbox cleared, just as before. Below you can see what the warning looks like.

Screenshot of the warning "The item is already in the list, please try again with a different value'.
3. Deactivate the “Add” button when relevant

It doesn’t make sense to me to add empty items in the list, so I want to deactivate the “Add” button when the textbox is empty. This is possible by changing the DisplayMode property of the button to the following:


The result

You can see the resulting behavior in the below clip. The tag box behaves as expected: adding and removing items to and from the list is possible, there is a check for duplicates, and it’s not possible to add empty items in the list.

Clip of the resulting UI element, adding some items, trying to add duplicates, removing items from the list and clearing the list.

If you want to set this up even more quickly and/or experiment with it, I have uploaded an canvas app containing just this setup to my github here.

Dynamically fill in a SharePoint multi-select person field using Power Automate

Multi-select person fields in SharePoint are quite common, but not straightforward to fill in using Power Automate when you have a variable number of people that could be added. In this post, I’m sharing a way that you can achieve this!

Identifying how to provide the data

To understand how this works, we first need to look at how SharePoint builds up a multi-select person field. For this, add a SharePoint “create item” action with a list that has a multi-select person field defined in it. (You can also use “update item” or “update file properties”) Then, where the multi-select person field is added, enter two dummy inputs by clicking “Add new item” below the first dropdown and providing some data. After entering the data, click the “T” icon in the top right corner of the field to switch to inputting the entire array, and there you’ll see the format of the array that is passed to SharePoint.

Click the “T” button to switch to input the entire array
The data that was entered will be transformed to the right format

This is the format that we need to provide the data in: an array (in between the square brackets) with objects (in between the curly brockets) that specify the “Claims” field, containing an email-address in between double quotes.

Creating an array

The easiest way to create an array in Power Automate is working with an array variable, and the “Append to array” built-in action. So to start, at the beginning of the flow, initialize a variable of type array and provide it with a meaningful name – in my case “CollaboratorsArray” since I will be adding a group of collaborators in an item in a list. Don’t supply an initial value.

Adding the necessary data to the array

Depending on where you’re getting the input email-addresses from, these steps will differ slightly. The basic idea is that for each emailaddress you want to add into the array, you have an “Append to array variable” action that will add an additional object to the array. You can do this with separate actions after each other if you want to combine multiple inputs into one, or you can do this inside a loop to add a list of emails.

In my case, I’m getting the emailaddresses that I want to add from a comma-separated string as a manual input from the flow. Therefore, I will need an “Apply to each” loop and will need to split the input string to get to the list of emailaddresses.

I’m first adding the “Apply to each” action to the flow, and adding the split function as the collection that the loop should iterate over. Afterwards, I add the “Append to array variable” action inside the loop and building up the object that needs to be supplied. So the value of your append action should have the following format:

   "Claims":"your value"

Providing the array to the SharePoint action

Now, all that’s left is to provide the array we built to the SharePoint action in the right location. To make this work, we should add the array into the right field in the “input entire array” option. This is the option where you don’t have the “Add new item” button.

The result will look like the image below. This will correctly fill the multi-select person field in SharePoint, and works when the number of people that are added can be different each time the flow is called!

Create a no-code button with icon (part 2)

A couple of months ago, I shared how you can create a button for navigation with an icon in a component and match its behavior to that of the “normal” buttons in canvas apps in this blog post. Back then, buttons created in this way could only be used for one specific action (in my case, navigating to another screen).

Since Power Apps added behavior properties to its canvas components, we can now extend this component solution so that a click on the button can trigger any function you want! Isn’t that cool? Let’s see how we can do this.

I’ll be starting from the button I created in that previous blog post. If you want to (re-)read that first, click this link.

⚠ If you’ve created the button component in a component library and are using it in applications, make sure that you make changes in a copy of the component, otherwise your other apps could stop working.

💡While this functionality is in preview, make sure to turn it on in the settings of your app or component library.

It’s quite easy to change the button so it can trigger any function when selected. Three steps is all it takes.

Step 1: Delete the “Screen” input property

Because we will change the component so it can trigger any function when selected, we don’t need the dedicated “Screen” property anymore. Therefore, we can simply delete it from the component. This will add an error to the component. Don’t worry about that for now, we’ll fix that in step 3.

Step 2: Add an “OnSelect” behavior property

Add a new custom property to the component and name it “OnSelect”. By choosing “OnSelect”, it will be straightforward for people familiar with canvas apps what they can expect this property to do. All controls that can be selected have this property defined, so it will be recognizable. The configuration is shown in the image below.

  1. Delete the “Screen” input property from the component
  2. Add an “OnSelect” behavior property to the component
  3. Trigger the “OnSelect” of the component when clicking the top button inside the component

Step 3: Configure the component to trigger OnSelect

The final step is to make sure that when the top button inside our component is clicked, this triggers the OnSelect property of the component itself. This is done by referencing the component’s OnSelect property in the OnSelect property of the top button.

Select the top button in your screen or from the tree view in the app studio and choose the OnSelect property from the property dropdown.

You’ll see that the function in the OnSelect property is still referencing the Screen property we deleted in the first step. This is why we’re getting an error. Replace the function in the function bar to simply reference the component’s OnSelect property as follows:


As a result, the error has disappeared, and we can now invoke any function we want when clicking the button inside our app by configuring the OnSelect property after we’ve added the button component.

Bonus: this is just like the standard buttons canvas apps provides, which makes it an intuitive solution, and you can offer this component to be used by beginning Makers without much risk.

With this new functionality, we’re not limited to navigation anymore, we can use it to patch data to a data source, show or hide controls on our app, etc. The possibilities are endless!

2020: a year in review

At the beginning of a new year, I like to reflect on what the past year has brought to learn and plan for the upcoming year so that I can start it on my terms.

2020 was an eventful year, to say the least. I believe no one was expecting it or prepared for it, I know I wasn’t. Just like everyone else, I tried to make the best of it. And just like everyone else, I had my ups-and-downs. So what did 2020 look like?


2020 was definitely the year that I started to be more active in the community.

In the beginning of the year, I started this blog. Even though I did not blog as consistent as I initially planned, I’m proud of the blog posts that I did publish. More importantly, I’m excited to continue blogging! That really is the main outcome I was aiming for. As I wrote in my very first blog post, I had tried blogging before and had given up, which I didn’t want to happen this time around. Of course, the universe threw some curveballs and there are some gaps. Despite this, I’m here in the beginning of 2021 and still blogging. And I already have some ideas I’m working on!

Just like I started blogging, I started speaking at conferences this year as well. I was fortunate enough to get the opportunity to speak at 2 live events before I was confined to the comfort of my own home indefinitely. Special thanks to Power Platform Saturday Warsaw 🇵🇱 for being the first ever conference I got the chance to speak at! I had some more events lined up that were cancelled and of course several of the organizers decided to move the event online. This resulted in 5 speaking engagements in total. A good start, and I’m eager for more. I’ve already got 2 events lined up for the first 2 months of the year, let’s hope more are added. And dare I hope for an in-person event towards the end of the year?


The theme for 2020 was courage. Stepping out of my comfort zone, trying new things and daring to question myself and my beliefs.

On the one hand, I had a lot of time for introspection because I had nowhere else to be but home. On the other hand, I found that the lockdown took away a lot of my energy and motivation. As an introvert, this was surprising since I get energy from being alone. I believe the uncertainty of when things will go back to “normal” is the main reason my energy level was down. It’s still challenging sometimes, and something I’m working on by trying to find stability and certainty in myself, instead of outside factors. It’s a journey…

Possibly the biggest surprise of 2020 was that in April I started running. And when I say started, I mean started from zero. My first run I averaged 7’52” for one kilometre. I followed a “start to run” plan and after 10 weeks I could run 30 mins straight. I was so proud of myself! To this day, I’m still running 3 times per week, and am on my way to running 10k. I never thought I’d say these words: I’m a runner. If nothing else, 2020 has made me a runner.

Not a picture of me, just to be clear

Some trivia

I read 13 books in 2020. Most memorable are Daring Greatly by Brené Brown and Good Morning, Good Life by Amy Landino. During my summer vacation, I took a trip down memory lane and teenage/young-adult nostalgia and re-read the entire Twilight series. I’m currently reading Sapiens by Yuval Noah Harari, also a recommendation if you want to gain some perspective on what we as humans have done in the time we’ve been on this planet.

We spent 1 week in the summer and the week between Christmas and New Year’s painting the majority of the house. Only two rooms left: my home office (picking colors isn’t easy!) and the guest bathroom downstairs. We plan on tackling those last two sometime in the next year.

I’ve picked up a new hobby in the last month: knitting. Completed projects are a headband, a blanket for our dog to lie in front of the pellet stove, a hat for my sister-in-law (Christmas present) and for my boyfriend. Currently working on a sweater for the dog. I’ve been looking for something creative to do in my spare time and knitting is fitting that gap nicely currently. Time will tell if it’s a keeper.

Looking ahead

2021 will come with its own set of challenges, opportunities and learnings. The theme for the year will be action. I spend too much time thinking (mostly doubting and second-guessing) and want to turn that into action. One of my guiding quotes is:

The only things you’ll regret in life are the things you didn’t do

I’ve started reading The Daily Stoic by Ryan Holiday. It’s a one-page-a-day book from which I want to get a daily piece of wisdom on the three principles of Stoïcism: control your perceptions, direct your actions properly and accept what is outside of your control. Three things that will help me in living according to my theme of the year.

On the professional side, I will continue to blog and speak at conferences (if they’ll have me 😊). Other than that, I’m working on something together with a community rockstar, that I hope we will be able to share with the rest of the community in the coming months. Stay tuned for that…

All that’s left is for me to wish you, from the bottom of my heart, a very happy and healthy 2021!

Expand and collapse rows in a Power Apps canvas app gallery

Galleries are one of the core components of Power Apps canvas apps, and there are many ways in which you can use them. Most often, they are used to show a list of information and give the user the option to click through to get even more information about the record or to take action.

In these cases, I’ve found it’s often difficult to decide what information to put in the gallery, and which to put in the detail screen. You need to balance the need for information with the screen estate and not having information overload. Therefore, it can be useful to show some basic information at first and giving the option to show some additional information by expanding the item before clicking through to the detail screen.

The result will look like this:

How can you create this? Let’s take a look…

Setting up the gallery

A gallery in which one item is expanded while the others are collapsed is in essence a gallery where different rows can have a different height. Therefore, you need to use a “flexible height gallery”. In other types of galleries, you cannot get to the same behaviour as you have in the example above.

Therefore, let’s start by adding a “Blank flexible height” gallery to the screen.

You can resize it so it fits your application. In my case it’s taking up the entire screen. Add the data source for the gallery and the controls that you need to show the information, including that which you only want to show when the item is expanded. You’ll notice that apart from the first row (which is the template cell), the height of all rows will adjust automatically when adding an extra control and moving it below ones that are already there. This is the main function of the flexible height gallery, and what we will use to create the expand/collapse effect: the height of each row adjusts to what is present in that row.

After adding the data, let’s add a down and up arrow icon to the gallery. They should be at the same X and Y coordinates, so they replace each other when collapsing/expanding. In my gallery, I’ve added a “more info” label and navigation icon as well so it’s clear when a user selects it, that they will go to another screen with more information. Also, I’ve added a line at the bottom of the gallery (which is a rectangle with tiny height) to indicate the different rows in the gallery.

Adding the collapse/expand functionality

What we want to achieve is that when a row is collapsed (which is default for the entire gallery), a user only sees the down arrow and can press it to show some additional information for this row (in my case the phone number and birthday).

When a row is expanded, the down arrow is replaced by the upwards arrow. This can be clicked by the user to collapse the row again and hide the additional information.

To make this functionality work, there are three things that need to be done:

  1. When selecting the “down” arrow, update a local variable “locInfoExpanded” to “true” and when selecting the “up” arrow, update a local variable “locInfoExpanded” to “false”.
  2. Set the “Visible” properties of the additional information, up and down arrow so they are visible at the right time
  3. (only when you have a separator between gallery rows) Change the Y position of the separator so it moves down when the row is expanded and up when it is collapsed

Arrow configuration

In the “OnSelect” property of the down arrow icon, add the following code:

Select(Parent); UpdateContext({locInfoExpanded:true})

In the “OnSelect” property of the up arrow icon, add the following code:

Select(Parent); UpdateContext({locInfoExpanded:false})

Visible properties

The “Visible” property of the additional information and the up arrow should be adapted to the following:

ThisItem.IsSelected && locInfoExpanded

Alternatively, that of the down arrow should be the opposite:

! (ThisItem.IsSelected && locInfoExpanded)

This ensures that the down arrow is shown for all rows that are not selected and for the selected one only if it is not expanded. If the arrows are placed at the same X and Y coordinates (and have the same height and width), it will seem as if they replace each other.

💡 Note: you can use just one icon control and dynamically change the displayed icon and executed functions as well by using if-clauses in the “Icon” and “OnSelect” property of the icon control.

Position of the separator

The position of the separator should change with the visibility of the additional information. More specifically: when the additional information is not visible, it should be placed right underneath the last visible item (in my case the address). When the row is expanded, the separator should be at the bottom (in my case right underneath the birthday.

To make it simple, I’m using the visibility of the birthday value label to determine where the separator should be placed instead of using the “Visible” formula.

The Y position of the separator should be set as follows:

    nameOfLastLabelInExpandedSection.Y + nameOfLastLabelInExpandedSection.Height + 2,
    nameOfLastLabelInCollapsedSection.Y + nameOfLastLabelInCollapsedSection.Height + 2

Which translates to the following in my case:

    lblBirthdayKey.Y + lblBirthdayKey.Height + 2,
    lblAddressKey.Y + lblAddressKey.Height + 2

The result

That’s it, you’ve built a gallery in which individual rows can be expanded to show additional information! This is what is should look like:

Using JSON to optimize Power Automate input parameters in the Power Apps trigger

This blog post is part of a 3-part series:

  1. Understanding default naming for Power Automate input parameters in the Power Apps trigger
  2. A uniform approach to Power Automate input parameters in the Power Apps trigger
  3. Using JSON to optimize Power Automate input parameters in the Power Apps trigger (this post)

In the previous two posts I published, I described how input parameters for the Power Apps trigger are created in a Power Automate flow and a solution to provide uniform naming for all input parameters in the flow. However, this is not a flexible solution. It can present inconveniences when adding an additional input parameter, or changing the setup of your flow where a certain input parameter is used in a different context.

In this blog post, which is the last in this series, I want to share an approach to input parameters that allows a lot of flexibility in the number and names of input variables: using JSON as input in the flow.

The method

Instead of creating an input parameter for all of the inputs that I need in the flow, I’m going to create one input parameter of type text. This input parameter will contain a JSON object (passed as a string), which will have fields for each of the desired inputs. What does that look like?

First, I’m going to add an “Initialize variable” action immediately after the trigger in my flow. This will be a variable of type string with the name “Inputs”. Just as in my previous blog post, I’m renaming the action to the name of the variable and then adding the “Ask in PowerApps” dynamic content. This will create an input parameter for the flow called “Inputs_Value”.

Insert a dynamic value 
Dynamic Value 
Search content from previous steps 
Ask i n PowerApps 
Learn more

This variable will be a JSON object. To get the contents of the JSON object, I’m adding a “Parse JSON” action after my variable initialization. The content to parse will be the variable that I created. I’m generating a schema by providing a sample JSON object that represents the input parameters I want to provide in my flow. Taking the same example variables as in the previous blog posts, this is the sample schema I’m adding into my flow:

    "ItemId": 1,
    "ItemTitle": "Title",
    "EmailSubject": "Subject of the email"
Insert a sample JSON Payload 
Clicking 'Done' will overwrite your current schema 
"Itemld": I 
"ItemTitIe" : 
"Title" , 
"EmailSubject": "Subject of the email" 

The schema is generated automatically. If I now add another action into the flow, my input parameters will be available as outputs of the parse action.

Send an email (V2) 
Carmen Ysewijn X 
Su bject 
Insert a dynamic value 
Dynamic Value 
p Search content from previous steps 
Parse JSON 
Item Id 
Item T it Le 
Learn more

If I add this flow into a Power Apps canvas app, there is only one text input variable needed, as you can see below.

uny• . Noscasued

The good and the bad

As mentioned before, this approach provides a lot of flexibility. If I need to remove an input, I remove it from the schema and don’t provide it in my app anymore. It will not still linger and be an extra input that I need to provide a value for even though it isn’t used anymore.

Adding an input is also relatively easy: I change the schema by adding a field and provide the extra input as part of the JSON string created in the app. This will have no impact on the trigger (it still expects one input parameter), and will not require me to remove and re-add the flow input my app before it works.

The main downside of this method is that if someone else is building the app and they are not aware that the input string should be JSON or which fields are expected exactly, they will not be helped by the hint in Power Apps studio. You can’t provide the correct inputs without having knowledge of the flow, or it being clearly documented somewhere.

Next to flexibility, another advantage of this method is that the trigger is completely separated from the logic in the flow. (The same goes for the approach using variables for each of the inputs described in my previous post.)  If you want to change the trigger of the flow to a different trigger (for example a manual trigger to be used as a run-only child flow with owner-provided connections), you don’t have to replace the input parameters everywhere in the logic of the flow. You only have to replace it once in the “Initialize variable” action. Every reference to that variable will remain intact, sparing a lot of work.

I believe this approach to input parameters provides a lot of flexibility that is currently missing for Power Apps triggered flows. Given good documentation, it can enable you to always have the right input variables available in your flow, without risks of breaking it or the app(s) it is used in when things change.

A uniform approach to Power Automate input parameters in the Power Apps trigger

This blog post is part of a 3-part series:

  1. Understanding default naming for Power Automate input parameters in the Power Apps trigger
  2. A uniform approach to Power Automate input parameters in the Power Apps trigger (this post)
  3. Using JSON to optimize Power Automate input parameters in the Power Apps trigger

In my previous blog post, I explained how Power Apps trigger input parameter names are generated based on the name of the action and the field it is used in. Since there are some drawbacks to the variety of names that are created this way, I want to share a uniform approach that I often use when working with a fixed set of input variables that I know is highly unlikely to change in the future.

The method

We know that an input parameter is generated using 2 parameters:

  1. The name of the action it is generated in
  2. The name of the field it is generated in

We can only control the first part, so to have a uniform naming, we should use one action that can generate different types of parameters within the same field. That action is “Initialize variable“. Using the “Type” field, you can differentiate between different types of parameters that can be passed by a Power Apps canvas app. The second part of the input parameter name will always be _Value (since this is the field that we generate the parameter in). You can then control the first part of your input parameter name by renaming the action before you generate the input parameter. That way, you have a uniform naming convention. Let’s take the same example parameters as in the previous blog post.

For the subject of the email and the title of the item we want to create, we can create a string parameter, for the ID we’ll use an integer. After adding three “Initialize variable” actions, filling in the name and type of the variable, we need to take two actions to create our input parameters for the flow:

  1. Rename the “Initialize variable” action to the name of the variable
  2. Add the “Ask in PowerApps” dynamic content in the initial value

The resulting input parameters will now have a name according to the following pattern: VariableName_Value. A uniform approach to input variables!

Itemld V 」 x 
ItemTitle Valu x 
EmailSubject Value x

The good and the bad

The great thing about using this approach is that all your input variables will show up using the same pattern in your app. When adding this flow to a Power Apps canvas app it’s easy to know what is expected in each of the input parameters thanks to these names.

Run(ltemld_Value, ItemTitle_Value, EmailSubject_Velue) 
Variableinputvariables . Runl

However, this is not a flexible solution. If tomorrow it is decided that the email is replaced by an approval, the input variable will still be called EmailSubject_Value. Or if the parameter is not used anymore in the flow, it will still be present and required as input parameter. When adding a new input parameter in your flow, you could have to remove and add the flow again in order to ensure that the changes on the trigger are picked up and your app doesn’t break.

Therefore, in the next and final blog post in this series I’m offering a flexible solution that addresses both these issues: Using JSON to optimize Power Automate input parameters in the Power Apps trigger.