Guides
How to Control Retool Table Loading State (Workarounds & Tips)

If you've tried to manually control the Retool table loading state — say, to show a spinner while a multi-step JavaScript query runs — you've probably hit a wall. By default, Retool only triggers the table's loading animation when its data property is bound directly to a query, like {{ myQuery.data }}. The moment you need something more dynamic, you're on your own. This guide covers exactly what's possible today, what isn't, and the best workarounds to keep your UI feeling responsive.
Why Retool Doesn't Let You Set Table Loading State Directly
Unlike buttons or text inputs — which expose an isFetching or loading property you can toggle — the Retool table component treats its loading state as an internal concern. It goes into "loading" mode automatically when its bound query is running, and comes out when data resolves. There's no equivalent of myTable.setFetching(true) you can call from a JS query. This inconsistency has frustrated developers for years, and as of this writing, Retool has not shipped a native fix despite acknowledging it as a feature request.
This matters most in a few common scenarios:
- You're running a multi-step JS query that transforms data before passing it to the table — the table doesn't know it should be "loading" during that transformation.
- You've added row-level action buttons inside the table and want the table (or the button) to show a loading indicator while the triggered query runs.
- You're using server-side pagination and want to show a loading state during page fetch without fully rebinding the table's data source.
The Best Workaround: Wrap the Table in a Container
The most reliable workaround right now is to place your table inside a Container component and use the container's built-in Loading property to show a loading overlay. Here's how to set it up step by step:
- Step 1: Drag a
Containercomponent onto your canvas and place yourTableinside it. - Step 2: In the Container's inspector, find the Loading toggle. Switch it from a static value to a dynamic expression using the
{{}}button. - Step 3: Bind the loading property to the query or state you want to track. For example:
{{ myQuery.isFetching }}will show the loading overlay exactly when your query is in flight. - Step 4: If you're using a JS query or a multi-step sequence, create a Retool State variable (e.g.,
isTableLoading) and set it manually in your script: callisTableLoading.setValue(true)at the start andisTableLoading.setValue(false)at the end. - Step 5: Bind the Container's loading property to
{{ isTableLoading.value }}. Now you have full programmatic control over the loading overlay.
This won't give you the exact native table spinner, but it produces a clean overlay that blocks interaction with the table while data is loading — which is usually what you actually need.
Controlling Loading State for Table Action Buttons
If your use case involves action columns inside the table — where clicking a button fires a query — you want the button or table to visually respond while that query runs. Unfortunately, action buttons inside tables don't inherit the same isFetching controls as standalone button components.
The practical approach here is the same container-level workaround. Bind your container's Loading property to the query triggered by the action button: {{ myActionQuery.isFetching }}. When a user clicks the action and the query fires, the container overlay activates automatically, preventing double-clicks and making the wait state obvious.
Using a State Variable for Full Manual Control
For the most flexibility — especially with server-side pagination or chained queries — a dedicated Retool state variable is your best tool. Here's a minimal pattern:
- Create a state variable named
tableLoadingwith a default value offalse. - At the top of your JS query, call
tableLoading.setValue(true). - After your data is ready and set, call
tableLoading.setValue(false). - Bind your Container's loading condition to
{{ tableLoading.value }}.
This pattern works cleanly with async/await in JavaScript queries and gives you precise control over exactly when the loading state starts and ends — something the native table binding can't do.
What Retool Has Said About a Native Fix
The Retool team has acknowledged this gap and confirmed it's on their radar — but as of the time of this writing, no native loading property has been added to the table component's inspector. Community threads on this topic have been bumped repeatedly over multiple years, which tells you how common this need is. If this is important to your workflow, it's worth submitting or upvoting the feature request directly in the Retool Community forum so it gets prioritized.
Summary: Your Options for Retool Table Loading State Today
- Native binding: Works automatically when you bind
datato a query via{{ myQuery.data }}. No extra setup needed, but zero manual control. - Container workaround: Wrap the table in a Container and bind its
Loadingproperty to a query'sisFetchingor a custom state variable. - State variable pattern: Create a boolean state variable, toggle it in your JS query, and bind it to the Container's loading condition for full programmatic control.
None of these are as elegant as a first-class myTable.setLoading(true) API, but they get the job done. Until Retool ships a native solution, the Container + state variable pattern is the most robust approach for production apps.
Ready to build?
We scope, design, and ship your Retool app — fast.