6 amazing ways to make your buttons more UI-friendly (in Retool)

Sophie Becker
October 1, 2021

One of Retool’s standout qualities as an internal tool builder is the ability to tie your company’s data management and analytics to effective actions, using a variety of powerful components and integrations. However, one thing we have recently observed within the Retool community is that, more often than not, this desire to turn data into actions often translates to an overwhelming amount of action buttons, whereby apps begin to resemble a ‘Where’s Waldo’ of that-button-I-need-to-submit-that-thing, rather than a slick user interface to streamline processes. Not only does this slow down work, but busy UIs also leave the potential for your users to make big mistakes. 

In the first instalment of Bold Tech’s UI sessions, we are tackling busy component enemy no.1: the button, to bring you some top tips for making better use of this powerful component, as well as some handy and innovative tricks to improve your UI even more.

So without further ado, to button tip number 1!

A Retool app with a table and at least 12 different blue buttons on the right side
“How to Push My Buttons”: A Horror Story in One Part

1. Keep Actions Dynamic Using Ternaries

The beauty of Retool’s dynamic features means it isn’t actually necessary to have an individual button for every action in your app. If you have multiple button actions which depend on the data you have selected (e.g. a selected row in a table), you can make use of ternaries to keep your button’s action dynamic, automatically adjusting to the needs of the data in front of you.

Here’s an example:

In the image below, you can see that our sales data has products that are either ‘online’ or ‘offline’, which is a key piece of data that we need to change from within the app. Instead of having two separate buttons to perform this action, our button automatically switches its action and text according to the row selected. This is how it looks in practice; note the ‘Switch to Online/Offline’ button above the table and how it changes depending on the row:

A gif showing a table component switching selected rows, each time the row changes the button changes color and the button text changes from 'online' to 'offline'

This is a very simple process that reads the data and changes the text, button color and query accordingly by using a ternary. The changing button color also improves the UI, making the action more obvious to the user to avoid mistakes. 

Let’s have a look at how this works. This is what the button text looks like:

text value for the online/offline button showing a ternary which switches based on backend data

And the button color:

background color value for the button showing a ternary

If you are unfamiliar with ternaries, they work just like ‘if/else’ statements: so these ternaries are checking if the first statement is true (the selected row = ‘offline’) and if so, performing the action after the question mark (changing the text or color). If the statement is false (i.e. the selected row = ‘online’), it performs the action after the colon. Ternaries are super useful for dynamic elements in your Retool apps, so if you aren’t already using them, they are definitely something worth trying to get your head around!

You would also need to apply the same principle in whichever query this button carries out, such as our query below. This query is triggered by an event handler ‘on click’ of the switch button we made above. 

query with a ternary which switches values accordingly

This dynamic action button is particularly useful for opposing actions or any kind of action that changes depending on the data itself. 

Note: if you’re managing more than two states for a button via a ternary, the syntax can get hairy pretty quickly. In that case, it may make sense to encapsulate a switch statement in a Transformer for cleaner routing.

2. Avoid unnecessary repetition in table components

While action buttons within tables make for a very simple UI, if each button performs the same action it means lots of wasted space within your app and a generally cluttered appearance. Take this same table for example:

A table in Retool with an action button column for 'edit details'

Since every button performs the same action, the repetition of the button doesn’t serve a useful function. Instead, you can use a single button that performs the action according to the selected row for a more streamlined interface, such as our ‘Edit Selected Item Details’ modal button as below:

a table component in Retool with a button above to edit details rather than in the table

In our case, this opens an edit modal, which responds to the data of the selected row in the table, filling in the details accordingly (see default value box). 

the default value for a text input in a modal

Note: the ‘Submit Changes’ button also needs to connect to a query that only updates the selected row. 

A better way to make use of Custom Columns and action buttons in table components is by using our tip in Step 1 to create dynamic buttons. For this, you would use a similar idea to the code in Step 1, this time using ‘currentRow’ instead of ‘selectedRow’, as in this example:

ternary which changes text and function of an action button accordingly

Just as in step 1, your action ‘on click’ would also need to connect to a dynamic query.

3. Use colour and shape effectively.

It’s a well-known tactic in marketing UI to use color to draw attention to the key action buttons which convert to sales - but this concept is not reserved for marketing alone, it can be really useful in internal apps too! By using color intentionally, developers can aid productivity by guiding users to the correct or important actions. 

We’ve seen many Retool apps defaulting religiously to the blue button that Retool provides as standard - and not only is this (sorry) really quite boring for the user, it also means that you are relying too heavily on the text of each action button. This means that your user needs to read (or remember the position of) each button before clicking, which can slow productivity, and once again, lead to silly mistakes. Color here helps to give the user some clues as to what each button does to speed up the processes within the app.

To illustrate, compare the two UIs here: 

a table component in retool with three blue buttons above

a table component in retool with three buttons above, one is white, one green and one blue

The simple changes to button color have made the actions much clearer and easier to discern:  the associated green/red of online/offline for our dynamic button helps indicate the kind of action that takes place. Then, the action of ‘Edit Selected Item Details’ (which is a key process for this app) is in a darker color to indicate its dominance and importance as an action, and the ‘View Product Details’ (which is a lesser-used, secondary action) uses an inverted white/blue color scheme to make it more subtle and allow the user to focus on the key action buttons instead. 

Here is another example of using dominant and then inverted colors to indicate key action versus secondary actions with our save/submit buttons: 

a modal showing edit details text inputs and two buttons, one says 'save without submit' and one says 'submit changes' in inverted colors

This simple change guides the user towards the most commonly used or important button.

On a similar note, you can also use the button shapes to differentiate between button types. In our app, we use buttons to switch between tabs in a container (we’ll get to that snazzy move later), but these buttons are less important than the action buttons for the data. So we changed the shape of each to reflect that difference: 

an app in retool: a table component next to a container which has three buttons above it as tabs

Although it may seem subtle and perhaps inconsequential, small details such as these can guide the user to the correct action buttons quicker and avoid confusion.

To summarize this section (and give you some extra ideas), here are some of our top tips for tactical button design: 

  • Use darker colours for the most used or most important actions to guide your user’s attention towards it
  • Use more toned down or inverted colours (e.g. blue text on white background) for less important or secondary action buttons to maintain focus on key actions
  • If relevant, use colors such as green for actions such as ‘Go’, ‘Validate’, ‘Submit’, ‘On’ etc and red for actions such as ‘Delete’, ‘Stop’, ‘Reject’, to give the user a clue before reading the button (people react to color quicker than they can read text!)
  • You can also use Emojis to enhance the meaning of the text on the button, such as alert sirens (🚨) for delete buttons or risky actions
  • Use button shape to differentiate between action buttons and buttons that interact with the UI, such as tabs

4. Give Your Users Feedback Using Event Handlers

Perhaps something that is overlooked within Retool apps is the indication to the user that an action, query or the like has been successful (or even unsuccessful). Good UI means giving your users a response to the actions if the results are not clear and immediate (such as data changing in a table - which may be obvious enough).

There are a few ways you can do this:

  • When you have submitted or saved changes within a modal, a simple trick is to set the modal to close upon success to indicate that the action has been completed. You can also use a form component, which will clear upon success, to show the successful submission. Here is how to close your modal on success by using an event handler in your ‘Submit Changes’ button: 

click handler in retool which closes the modal on click

  • For another simple success indication, use confetti - everybody loves confetti! (And digital confetti requires no clean up). You can do this in the event handlers of your button (on click) or in your query (on success) like so:

success handler in retool which triggers confetti on success

  • Another great option, which also allows you to add text explanation for specificity is the event handler option ‘Show Notification’, which you can set to appear for Success or Failure and change the message accordingly for the user. Here is an example for our ‘Delete Product’ query:

success handler which triggers a 'successfully deleted' notification on success

  • Upon success, you would see this notification, which simply helps the user to know what has taken place and that their action has been successful, but will also indicate what exactly has happened in case of a mistake - to give the user the chance to rectify this:

example of a notification in a retool environment

5. Avoiding Mistakes: Disable Button Options 

UI is not only about making processes easier, but also making it harder to make mistakes. Cluttered UI interfaces with button overload make it just as easy to click ‘Delete Client’ as ‘Create Client’ - and therefore creates space for big problems. 

There are a couple of validation options within Retool to avoid these kinds of mistakes and these are great to implement in apps, particularly when the actions are risky and need extra layers of verification. 

The easiest option is adding a validation within your query, which you can do in your query settings as below: 

delete row query with confirmation message

This simply creates an extra step between clicking a button and performing an action, which avoids risky mis-clicks.

Another way to avoid accidental clicks is to add a simple Captcha-style task, such as our ‘type YES to verify’ option here: 

send email modal with a confirmation message and 'type YES to continue' validation

Since the ‘Send’ button here will allow someone to email a client, we want to double-check that the app user is sure they are ready to send. One step was by adding a simple alert message to get their attention (the alert component), and the other is by using a text input component which enables the button. 

To make this work, simply add the following reference to the ‘Disable When’ section of the button component:

button disabled when validation input does not equal yes

This means that unless the text input contains the string ‘YES’, the action will not be clickable, and adds an extra degree of separation between the user and that accidental ‘hit send’. 

Another handy option to avoid these critical mistakes would be to disable the buttons for certain user groups who do not need access to these actions. You can do this by adding user permissions in your Retool settings and adding a ternary like this to your ‘Disable When’, which only enables a button if the current user is in the ‘Managers’ group. 

{{!current_user.groups.map(group => group.name).includes('Managers')}}

6. Get creative with other components! 

Actions don’t need to be tied exclusively to the button component, and buttons can also be used in place of other, more typical components, for both UI and style reasons. For our final tip, we have a bumper selection of tips and tricks to use other components like buttons, and buttons like other components (in all kinds of exciting and unexpected ways!):

Use buttons as tabs for a slicker UI

The tabbed container component - while useful - is not exactly the prettiest. In fact, we don’t really like the appearance of the standard tabs at all. This is why we’ve created a snazzy (albeit more complicated) way of switching tabs using buttons instead of ordinary tabs! This is how it looks:

a gif showing switching between tabs using buttons

Here’s how to use this trick yourself:

First create a temp state (by clicking ‘Create New’ under Temporary State in the left panel) and label it for clarity:

temporary states to change tabs

Then insert your tab buttons and name them accordingly. 

Note: we don’t use a button group here simply because the component itself is not very responsive for different screen sizes, and we want our buttons to always remain in line to make their function clear. If using a button group - you simply need to follow the event handlers step and skip the temp states)

Now you want each button to change the value of the temp state on click - to do this you’ll use the event handlers within the button component. First create an event handler that selects the relevant tab when the button is clicked, like below:

click handler for a button which switches tab on click

So now, when the button is clicked, it will control the tabbed container and switch the tab to ‘0’ (the details tab). 

Then, add another event handler that sets the temp state value:

click handler for button which changes temporary state

You’ll use this event handler to change the color of the button according to which is selected, using the code below: 


{{changeTabs.value == 'Details' ? "#67AAE4" : "#FFFFFF"}}


{{changeTabs.value == 'Details' ? "#FFFFFF" : "#67AAE4"}}

color settings for buttons - colors switch using a ternary according to temp state

This ternary will set the color to blue text on white when the button/tab is not selected, and white text on blue when that button and tab is selected. 

Do this exact process to each of your buttons and tabs, only changing the temp state to an appropriate, unique value each time. 

Once that is complete, make sure to set the default value of your temp state (in the left-hand column, click the ‘Temporary State’ you created and change this value in the right-hand column) to the tab you would like the app to open on. 

initial value of the temp state

And with that you are done creating more beautiful, and more customizable, buttons for your tabbed container!

Buttons in Place of Switches

Switches (or toggles) are handy for true/false values, but they don’t always make the most sense when it comes to certain UI functions, where the switch doesn’t naturally indicate whether something is on or off. An example is a show/hide container function, where the button changes dynamically to change the action. Here’s how it looks in practice: 

gif showing 'overview' drop down - on click the header expands to show two cards with stats on

Like the buttons in place of tabs, this works using temp states to indicate whether the action is true/false or on/off (or even multiple options).

First, like above, create a temp state (by clicking ‘Create New’ under Temporary State in the left panel) and label it for clarity:

temporary state for the show/hide feature

Set the state’s default value by selecting it in the left-hand panel and editing it in the right-hand panel, in our case we wanted it set to ‘true’.

show/hide button initial value is true

Next to whatever components you wish to show or hide, add a button. In the button text section add a ternary that changes the button text dynamically according to the value of the temp state:

show overview button settings - text switches from show to hide using a ternary

Then add two Event Handlers which sets the value of the temporary state to true and false, back and forth, by basically completing the opposite action, as below: 

click handler for show/hide button which switches temp state
click handler for show/hide button which switches temp state

Essentially, the first event handler sets the value to false (the default is true) on click, but will only do so if the temp state is currently set to true, and the second event handler sets it back to true on a second click (again only if the temp state is currently false - to create a cycle). 

Once this is done, you just need to set the relevant components to hide, by adding this to your ‘Hidden’ value box (where showHide.value is the temp state):

'hidden' value for the containers - hidden when temp state = true

This true/false button in place of a switch creates an intuitive action with a slicker UI than a toggle.

Dropdown action bar

If you take one thing away from this tutorial, it should be this one. Our final, and snazziest, Retool hack is super simple and is one of our absolute favourites - we use it across many of the apps that we develop. In essence, it takes a series of action buttons (e.g. edit, view, send, save, upload documents) and condenses what would be many buttons into a simple action dropdown. 

This is how it looks:

gif shows dropdown selection opening modals

It’s good, right?!

It works by triggering modals to open when the option is selected by using event handlers (which can also be linked directly to queries where needed).

To get started, insert your modal components into the app, set them up however you need, and then hide the button itself by adding ‘true’ to the ‘hidden’ value box. 

edit modal button settings, hidden when true

Then add a dropdown/select component to your app and label it ‘Action’.

Set the values of your select component however you need. Here is how ours looked:

dropdown settings show values

Then, in the event handlers, set the values to trigger the modals to open. Here is our ‘Edit Details’ modal as an example:

dropdown settings, click handlers which trigger modals to open when selected

Now, when the dropdown value changes, the editModal will open, but only if the value changes to ‘Edit’. Do the same with your other modals. 

You can also connect this straight to a query, just like our ‘delete’ action: 

dropdown click handler sets query on click

When ‘delete’ is clicked, the delete query will run. 

Finally, you can use a JavaScript query to set the dropdown to clear each time the value changes, so that you can select another option or reselect the same one.

Here is your query, which simply sets the dropdown value to empty (“ ”):

javascript code to reset dropdown value after selection

And here is how to trigger it from your dropdown:

change handler triggers javascript clear dropdown on change

And with that you are all done! 

Have these tips helped you improve the UI of your app at all? Have you used any of our tricks in new and unique ways? We’d love to know! Send an email to sophie@boldtech.dev, we’d love to hear from you!

Subscribe to get updates when we post
Thanks for subscribing!
Oops! Something went wrong while submitting the form.

Joey has been an absolute pleasure to work with! He’s provided a lasting impact on our organization by building out our Retool portal in a way that allows us to optimize how we track, communicate and launch our clients. His attention to detail and rapid ability to implement all of our product requests was unmatched. I highly recommend the Bold Tech team for all things related to Retool!!

Justin Gage Testimonial - Founder of Technically and Growth at Retool
JP Morales, Strategic Partnerships
Mammoth Climate

Joey and the team at BoldTech have been amazing partners to us from the start, helping us turn our proof of concept into paying enterprise contract in a matter of months. They feel like a natural extension of our team, and we have been incredibly impressed by their ability and willingness to dive into a complex domain and be strategic thought partners in solving nuanced workflows and complex data problems.

Justin Gage Testimonial - Founder of Technically and Growth at Retool
Julia Cohen - Founder