We often encounter situations where built-in Retool widgets struggle: you need to display 10k+ points on a map with dynamic clustering, but the native Map widget freezes at 500 points. Or you need a chart with custom animation, drag-and-drop sorting with business rules, a Kanban board with WIP limits. For such tasks, Retool provides Custom Components — full React applications isolated in an iframe and communicating with the host via postMessage API. We have built over 50 such components turnkey for various business tasks, and we share the accumulated practice.
How custom components work — custom Retool components development
A Custom Component is a React application that communicates with Retool through the @tryretool/custom-component-support library. It provides React hooks for state synchronization: Retool.useStateValue for reading/writing the model and Retool.useEventCallback for sending events back to Retool. The development environment is a local server (Vite or CRA), and the production bundle is deployed to any static hosting.
// src/index.tsx — entry point of the custom component import { Retool } from '@tryretool/custom-component-support'; interface ModelData { items: Array<{ id: string; label: string; value: number; color: string }>; selectedId: string | null; } export const BubbleChart: FC = () => { const [items] = Retool.useStateValue<ModelData['items']>({ name: 'items', initialValue: [], label: 'Chart items', inspector: 'array', }); const [selectedId, setSelectedId] = Retool.useStateValue<string | null>({ name: 'selectedId', initialValue: null, label: 'Selected item ID', inspector: 'string', }); const onSelect = Retool.useEventCallback({ name: 'onItemSelect' }); const handleBubbleClick = (id: string) => { setSelectedId(id); onSelect({ id }); }; return ( <BubbleChartRenderer items={items} selectedId={selectedId} onSelect={onSelect} /> ); }; Why custom Retool components are better than built-in widgets?
Built-in widgets cover 80% of typical tasks, but the remaining 20% require a custom solution. Compare:
| Criteria | Built-in widgets | Custom components |
|---|---|---|
| Visualization | Standard charts (bar, line, pie) | Any: D3.js, Three.js, ECharts |
| Interactivity | Basic (filters, sorting) | Custom events, drag-and-drop, animations |
| Performance | Limited to 1–2k rows | Virtualization up to 50k+ rows |
| Flexibility | Fixed properties | Full control over rendering and logic |
For rare formats (chord diagram, force-directed graph), a custom component is the only way.
Typical tasks
Visualizations: D3.js charts (chord diagram, force-directed graph, sankey), ECharts with custom series, Three.js 3D model previews. For example, a client achieved a 40% performance boost using a custom Retool D3.js visualization over native charts.
Interactive tables: virtualized lists using @tanstack/virtual for 50k+ rows, inline editing with custom validators, drag-and-drop sorting via @dnd-kit/core. This enables Retool drag-and-drop workflows.
Maps: Mapbox GL JS / Leaflet with dynamic clusters, drawing tools for geofences, isochrones via Mapbox Isochrone API. Perfect for Retool interactive maps.
Specific UI patterns: Retool Kanban board with business constraints, Retool Gantt timeline, code editor based on Monaco. These cover advanced Retool custom component integration needs.
What's included in the work?
We develop the component turnkey: from data contract design to deployment and documentation. The scope includes:
- Agreeing on the data model and events.
- Implementing rendering and all business logic.
- Integration with your Retool environment (cloud or self-hosted).
- Performance optimization (virtualization, lazy loading, memoization).
- Deployment to CDN or Retool Toolbox.
- Documentation for installation and use.
- Training and written support for 2 weeks after delivery.
Build and deploy
The component is bundled into a single file and deployed to static storage. Retool supports two connection methods: via URL (CDN/S3/Vercel) and via Retool Toolbox for self-hosted instances.
// vite.config.ts import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], build: { lib: { entry: 'src/index.tsx', name: 'RetoolCustomComponent', fileName: 'index', formats: ['umd'], }, rollupOptions: { external: ['react', 'react-dom'], output: { globals: { react: 'React', 'react-dom': 'ReactDOM', }, }, }, }, }); After vite build — the dist/index.umd.js is uploaded to a CDN or Retool Cloud Storage. In the Retool interface, you create a Custom Component, specify the bundle URL and the iframe page URL.
Passing complex data
Retool limits the model to serializable types. For complex structures (nested objects, files), use JSON serialization inside a string field:
const [rawConfig] = Retool.useStateValue<string>({ name: 'config', initialValue: '{}', label: 'JSON Config', inspector: 'text', }); const config = useMemo(() => { try { return JSON.parse(rawConfig); } catch { return {}; } }, [rawConfig]); For large datasets (thousands of rows), data is passed through a Retool Query that returns JSON — the component receives it directly without duplicating state in the model.
How to create a custom component: 5 steps
- Set up the project: create a React app with Vite or CRA, install
@tryretool/custom-component-support. - Define the data contract: agree with the client on model fields (entries, properties) and events (callbacks).
- Implement rendering and logic: use
useStateValuehooks to read data anduseEventCallbackto send events. - Build the bundle: run
vite buildwith UMD configuration. - Deploy: upload the bundle to a CDN or Retool Toolbox and provide the URL in the Retool interface.
Our experience and guarantees
We've been working with low-code platforms for seven years and have built over 50 custom components for Retool. We guarantee stable operation and adherence to deadlines. Contact us — we'll assess your task for free. Development cost varies depending on complexity, but typically pays for itself within 2–3 months of use. Typical project costs range from $2,000 to $10,000.







