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:
- Add a modal option to disable every interactive element in the app that's outside the modal
- 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)