A starter template for creating custom React components for Retool using TypeScript and React. This project includes a simple counter component that demonstrates how to use Retool's state management and event handling.
Retool now allows for writing your own components using TypeScript + React. You can easily pass data between custom components and existing components available in the drag-and-drop GUI.
Retool is great for internal tooling because it allows you to write SSO-auth protected internal tools and has existing permissions to perform common actions which query or modify your database.
However, because Retool is a no-code platform it can be difficult to maintain or create more complex apps. Custom React components allow us to create more complex internal tools which can be more quickly updated via code changes.
- Simple counter component with increment functionality
- Mock implementation for local development
- Integration with Retool's state management
- Event handling for API calls and operations
- TypeScript support
- Hot reloading during development
git clone https://github.com/Whatnot-Inc/retool-custom-react-component-starter
cd retool-custom-react-component-starternpm install
npm startGo to localhost:3000 and you should see this basic React component:
If you don't have them already, you'll need admin permissions in your Retool instance to create and deploy custom component libraries
From the repo root, run:
npm run initSelect "Log in to your own self hosted Retool instance" and paste your Retool URL (e.g., https://your-company.retool.com).
Then go to your Retool instance's Settings → API (https://your-company.retool.com/settings/api) and create an access token with read and write access to Custom Component libraries, and paste it in.
Finally, name your library and give it a description.
The component library name (e.g., "MyCustomComponents") will show up in Retool's component search:
When you're ready to deploy your component, uncomment the Retool import line in src/MyRetoolComponent.tsx to use Retool's state binding library. This will allow any state variables created via Retool.useState… to be referenced in other components in the same Retool dashboard.
import { Retool } from '@tryretool/custom-component-support'
// import { Retool } from './mocks/retool';Now deploy your component by running:
npm run deployGo into your Retool app and search for your component:
Drag and drop your component into your dashboard:
You can now use your component as well as reference the state variables you exposed via the Retool.useState… methods:
If you make a change to your custom React component, run npm run deploy again, refresh the Retool page, then select the latest version of your component:
That's the basics! For more advanced topics like making API calls from custom components via Retool queries/scripts, see below.
For local development, the project includes a mock implementation of the Retool API:
- Open
src/MyRetoolComponent.tsx - Comment out the Retool import and uncomment the mock import:
// import { Retool } from '@tryretool/custom-component-support'; import { Retool } from './mocks/retool'
- Start the development server:
npm start
This allows you to develop and test your component without needing to connect to Retool.
When you're ready to use your component in Retool:
- Open
src/MyRetoolComponent.tsx - Uncomment the Retool import and comment out the mock import:
import { Retool } from '@tryretool/custom-component-support' // import { Retool } from './mocks/retool';
- Build the component:
npm run build - Deploy to Retool:
npm run deploy
npm start- Start the development servernpm run build- Build the component for productionnpm test- Run testsnpm run login- Log in to Retoolnpm run sync- Sync changes to Retool during developmentnpm run deploy- Deploy the component to Retoolnpm run init- Initialize a new Retool component
src/MyRetoolComponent.tsx- The main component filesrc/MyRetoolComponent.css- Styles for the componentsrc/mocks/retool.ts- Mock implementation of Retool API for local developmentsrc/index.tsx- Entry point for local developmentsrc/retool-entry.tsx- Entry point for Retool deploymentpublic/- Static assetsdist/- Built files for deployment
To customize the component:
- Modify
src/MyRetoolComponent.tsxto add your own functionality - Update styles in
src/MyRetoolComponent.css - Add additional state using Retool's state management hooks:
useStateBooleanuseStateNumberuseStateStringuseStateEnumerationuseStateObjectuseStateArray
This starter uses Retool's state management through hooks. In the counter example:
const [count, setCountState] = Retool.useStateNumber?.({
name: 'count',
initialValue: 0
})This creates a state variable that is managed by Retool, allowing the state to be accessed and manipulated from the Retool interface.
Exposing custom component state is relatively simple (use Retool.useState… methods, as seen in the examples above).
In this section, we'll cover how to make API calls which will execute some code outside our custom React component (e.g., some Retool query/mutation, execute some script in your Retool dashboard, etc.) then return data to our custom React component.
Expose a new "event callback" in your custom React component to your Retool dashboard:
Retool.useEventCallback({
name: 'runQuery',
})Deploy your change to Retool via npm run deploy, refresh Retool, then select the latest version of your component:
You should now see the Event handlers section show up in the "Inspector" when selecting your component in Retool:
Add an event handler to handle the runQuery event you just exposed and choose the query, script, etc., that you want this event to run in Retool:
If you need data to be returned from the Retool operation, create a new stateObject variable on your component which you'll use to store the operation result and pass it to your custom component.
For this example, let's assume we're saving some data in a variable called customerStatus:
const [customerStatus, setCustomerStatus] = Retool.useStateObject?.({
name: 'customerStatus',
initialValue: {}
})Deploy your changes via npm run deploy and update your component version in Retool.
Select your custom component and pass the result of your Retool operation by setting the value of the customerStatus state object:
Retool operations are performed async relative to your custom React component, so you'll need to monitor for changes on this variable. In the example below, we can listen for changes on the customerStatus value and store it in a customerStatusRef object:
const customerStatusRef = useRef(null);
useEffect(() => {
customerStatusRef.current = customerStatus;
}, [customerStatus]);Unfortunately there is no support for direct callbacks on Retool state changes, so to fetch the result of our operation from within our custom React component we'll use a polling or timeout approach that will look something like this:
const waitForResult = async (timeoutMs: number) => {
const startTime = Date.now();
while (Date.now() - startTime < timeoutMs) {
if (customerStatusRef.current) {
return customerStatusRef.current;
}
await new Promise(resolve => setTimeout(resolve, 100));
}
return null;
};
// Usage
const result = await waitForResult(5000); // Wait up to 5 secondsThe flow is:
- We trigger an event in our Retool dashboard from our custom React component called "runQuery"
- Our "runQuery" event is handled in our Retool dashboard to make some operation (query/mutation, call some script, etc.)
- The result of our operation is passed into our custom React component via the
customerStatusstate object - We add a listener on changes to the
customerStatusobject and store it in arefvariable in our custom React component - We wait X ms for the above async operation to complete and update our
refvariable, then we read thecustomerStatusRef.currentvalue
This project is licensed under the MIT License - see the LICENSE file for details.

















