Disable everything behind modal with background opacity

We're using modals extensively and have run into issues where users are clicking buttons and other interactive components outside the modal, with unexpected results.

With the help of Retool's support team, we've come up with a workaround that allows us to at least disable all the components behind the modal, but this approach is difficult to maintain, as we need to remember to update the custom CSS every time we adjust anything about the app that might introduce new components.

The custom CSS is... challenging... given the number of elements we have to disable when modals are open, and the number of modals in the app. Using inline JS with the {{ }} notation, line breaks aren't supported, as far as we can tell (maybe there's a trick to this we aren't aware of?).

So we tried using a transformer where we could better format the JS, only to discover this in the doc...

Transformers in Retool are read-only - they cannot affect the values of other components or state in Retool. They can only update their own value via a return statement. This means that if you're writing JS in a Transformer, you cannot:

  • Set the value of temporary state
  • Set the value of a component
  • Trigger a query

To do any of these, you'll need to use a JS Code query.

We then tried a JS query, but that didn't work either (maybe because we did something wrong???). So our current custom CSS text element has this monstrosity:

/* disable all main screen elements when a modal is open */ {{ ( modalGenerateDraftPayouts.opened || modalPayoutNew.opened || modalPayoutNewDetail.opened || modalPayoutDetailEdit.opened || modalPayoutDetailNew.opened || modalPayoutDetailUpdateAch.opened || modalPayoutDetailView.opened || modalProcessPayouts.opened ) ? "#navBar, .ant-tabs-nav-container, ._retool-btnPayoutsApprove .ant-btn, ._retool-btnPayoutsApproveDetail .ant-btn, ._retool-btnPayoutsDoNotPay .ant-btn, ._retool-btnPayoutsDoNotPayDetail .ant-btn, ._retool-btnPayoutsDraft .ant-btn, ._retool-btnPayoutsDraftDetail .ant-btn, ._retool-btnPayoutsToggleSelected .ant-btn, ._retool-inputFindRiderPayout .ant-input,._retool-modalPayoutNew-modal-button .ant-btn, ._retool-modalPayoutDetailUpdateAch-modal-button .ant-btn, ._retool-modalPayoutDetailNew-modal-button .ant-btn, ._retool-modalGenerateDraftPayouts-modal-button .ant-btn, ._retool-modalProcessPayouts-modal-button .ant-btn, ._retool-tblPayoutsDraft, ._retool-tblPayoutsDraft .ant-btn, ._retool-tblPayoutsDraft .ant-checkbox, ._retool-tblPayoutsDraftDetail, ._retool-tblPayoutsDraftDetail .ant-btn { pointer-events: none !important; }" : "" }}

While this approach works, it's incredibly painful to maintain as the app changes, and highly prone to errors if we forget to update it when any new interactive component is added to the app.

We'd like to disable and darken everything behind the modal.

So, the feature request:

  1. Add a modal option to disable every interactive element in the app that's outside the modal
  2. Add a modal option to add an overlay to everything outside the modal, with custom opacity (similar to what happens when you click the Open Modal button at W3.CSS Modal)
1 Like

Thanks for the thoughtful feature requests here @laurab! I think these are both sensible and useful requests that we should make next year. Right now our team is on holiday break through the first week of January, but I’ve tracked your request and will update you here once we make some progress on it. Happy holidays!

2 Likes

Hey @alex, just wondering if this feature is on the cards for a future release or if I should go ahead and use @laurab's CSS solution?

I've got a similar issue where clicking outside the modal has the capacity to seriously mess things up so I need to disable everything behind it.

Cheers!

Hi @krausenhaus — thanks for reviving this thread! Your post sparked an idea for me and I was just able to figure out how to dynamically disable the canvas when a modal is open. This solution is designed to only exhibit this behavior in end user mode, but you could also customize the CSS to work in edit mode as well.

CC: @laurab since you will probably be interested in this too :slight_smile:

Note: This method relies on our deprecated Text component and the old way of adding Custom CSS to Retool. I mention this as a word of caution. Unfortunately, our new Custom CSS panel doesn't allow for dynamic CSS, which we need for this behavior. More about deprecated features in our docs here.

Here are the steps:

  1. Go to the /settings/beta page of Retool and enable the Deprecated components option.

  2. Add a Text (deprecated) component to the canvas. Enable the option to "Render as HTML" and disable the option to "Render as Markdown. Then add add the following code:

<style>
  .retool-modal-component-wrapper {
    background-color: rgba(0,0,0,.3);
    z-index: 10000000 !important;
  }
  
  .retool-canvas{{modal1.opened ? '' : '-disable'}} {
    pointer-events: none !important;
  }
  
</style>

It should now look like this:

  1. This should now be working in presentation (aka end user) mode! Go ahead and test it out.
3 Likes

You're a legend, @alex, works perfectly! Thank you!

1 Like

THANK YOU @alex !!! This is so so so much easier to deal with.

Now if there's a way to get it to work in Edit mode, it'd be just about perfect.

I assume Retool will continue to support deprecated features like this text box pretty much forever, so existing applications won't break down the road?

@alex - There's an issue with this approach if you fire any queries from within the modal that require confirmation. In this case, the confirmation modal appears behind the existing modal (I assume because of the z-index added to the wrapper in this solution). I've disabled that for now, and the rest of the solution still works (to disable everything behind the modal).

1 Like

Nice @alex! FWIW, I decreased the z-index to 1000 so that tooltips in my modal wouldn't appear behind the overlay (tooltips seem to be at z-index: 1060). Seems to work while still keeping other things unclickable.

2 Likes

I'm running into another problem with this workaround that I've been unable to solve... @alex or @jeffbowen, perhaps you've encountered this and have a solution?

When there are multiple modals in the app, and those modals contains Date/Time or Select components, those components no longer work correctly with this custom CSS in place. (They work fine without it.) The pop-up calendar or options list appears, but neither are clickable so nothing can be selected from them. I've tried overriding pointer-events for these elements without success. I'm probably missing something simple here, I just can't find it.

I have a tiny generic test app set up that demonstrates the problem. Happy to provide that if anyone wants to take a look.

I haven't run into that yet @laurab. Have you tried decreasing the z-index to 1000?