Button with loading indicator

In this quick tutorial, we’ll show you how to create a Button that shows an in-place loading Spinner when the user presses on it, then changes back once the loading is completed. While the Button is loading, the user cannot interact with it.

Here's how the Button will look when tapped after completing this tutorial

This can be useful with actions that aren’t instant and take a while, e.g. complex backend requests, if you don’t want to show a Spinner that covers the whole page.

Defining the Button action

We start by dragging a Button that will trigger a long action to UI canvas. (If you already have some Button in your app where you’d want to implement this loading indicator, you can always use an existing Button instead.)

Here we use Delay flow function to represent the long action.

Instead of Delay, your Button will likely have some complex logic to e.g. query a backend

Creating the loading indicator

Now that we have the Button that should indicate when an action is underway, we can build the loading indicator. Simply drag a Container under the Button and drag a Spinner inside the Container. This Container will replace the Button during the long action.

It's good practice to name the Container to something descriptive, e.g. Loading Indicator Container.

Under the Style tab in the right-hand properties panel, ensure that the Dimensions and position of the Container match the ones of the Button. Also, set the Container to Justify content vertically to middle, so that our Spinner is aligned correctly to the middle.

Min height 56px and 8px margins are copied from the Button

Then you can add some Borders, Background color and other styles to your Container depending on how you want the Button to look during the Loading phase. Here we set the Borders (and Spinner) to a gray color and change Border radius to 3px to match the Button.

You can change the Spinner to be large in the Properties tab

Showing the Loading indicator

Now we have just a Button with a Container and Spinner under it always visible, which means we have to create the logic to show only either one of them at a time.

First, create a Page variable actionInProgress and change its type to True/false. Then, open the Advanced properties section of the Button Properties tab and bind the Visible value to a formula:


You can also use shorthand ! instead of NOT() formula

This means the Button will be visible when the value of actionInProgress is False.

For the Container, you can bind the Visible property directly to actionInProgress, so that it's shown when actionInProgress is True.

Thus, switching the value of the actionInProgress page variable now switches which component is shown.

Lastly, you need to toggle the actionInProgress page variable to True when your Button is tapped. Remember to toggle the value back to False when the action ends, even if your complex action has more outputs that the Delay we are using here. Be sure to cover potential error paths too!

That’s it! Now your Button indicates the user that the action is underway.

Note: With this same logic, you can replace also other parts of the UI during actions. For example, you can change some “Send message” icon into a Spinner, or just show a Spinner in other part of your page.

Advanced: Loading indicators for repeated Buttons

You have now mastered the basics of indicating a loading state in your app through toggling the Visible property of components. Now it’s time to dig in a little deeper: how to show the loading indicator on the correct Button if the Button is in a repeated list?

After advanced section loading indicators will work with repeated Buttons

Repeated Container

First, add the Button and the Loading Indicator Container created in previous steps into another Container (we'll name it Repeated Container).

Bonus, part 1/2 You can add a Title component to the top of the Repeated Container to make the Repeated Containers look more distinct between each other.

Containers are renamed in Composer for clarity

Then, under the properties panel, change the Repeat with property of the Repeated Container to be bound to the data you want to repeat (which needs to be of type List of Objects).

Here, we use mock data through a formula binding:

[{"name": "first", "id": GENERATE_UUID()}, {"name": "second", "id": GENERATE_UUID()}, {"name": "third", "id": GENERATE_UUID()}, {"name": "something", "id": GENERATE_UUID()}, {"name": "else", "id": GENERATE_UUID()}, {"name": "indeed", "id": GENERATE_UUID()}]

Note: Each of the items has to have a unique property for this configuration to work. Here we have the id property created with GENERATE_UUID() formula function.

Bonus, part 2/2 Bind the Title content to Property of data item in repeat >name.

Toggling visibilities

Now, instead of page variable actionInProgress we need a page variable that can sort out the exact actions/buttons that are in progress.

Create a new page variable actionIdsInProgress and change its value type to List. (Here we could also change List item type to UUID, but that’s not necessary, the default Text type works fine).

We’ll use actionIdsInProgress to contain theid properties of repeated data items that have their related Button tapped. To add the related id to the List, change the first Set page variable in the Button tap event to set actionIdsInProgress with formula:

WITH_ITEM(pageVars.actionIdsInProgress, current.id)

This sets the actionIdsInProgress list to be itself plus the pressed Button's id.

Then, after the action of the Button (the Delay node in this example) completes, change the second Set page variable to set actionIdsInProgress back to not include the related id with formula:

WITHOUT_ITEM(pageVars.actionIdsInProgress, current.id)

Lastly, you have to bind the Visible properties of the Button and Loading Indicator Container to the values of the actionIdsInProgress. Each Button should be visible if the actionIdsInProgress List doesn’t include their id and invisible if their id is in the List. This can be accomplished with another formula:

!IS_IN_ARRAY(pageVars.actionIdsInProgress, current.id)

For the Loading Indicator Container just remove the ! from the beginning and it will be visible when the id is in the List.

Done! Now you know how to handle visual changes in repeated components.

Note: You can use this same logic with other types of user interface components when working with repeated data. For example you can create accordions or show/hide fields in the repeated Container depending on the value of a Checkbox.