One floating button for all your dev tools.
A draggable dev panel for React Native QA builds. Network Chaos, Timewarp, A11y Lens and your own tools plug in as tabs, and the button shows what's active.
npm install @helder-studio/dev-dockEvery dev tool wants its own floating button. Three tools later, half the screen is badges. Dev Dock gives them one button and one panel, and the button still tells you at a glance that the network is flaky and the clock is on New Year's Eve.
import { DevDock } from '@helder-studio/dev-dock';
import { NetworkChaos, networkChaosTab } from '@helder-studio/network-chaos';
import { timewarpTab } from '@helder-studio/timewarp';
import { A11yLensOverlay, a11yLensTab } from '@helder-studio/a11y-lens';
const qa = __DEV__ || Config.QA_BUILD;
<NetworkChaos enabled={qa} storage={storage} badge={false}>
<App />
<A11yLensOverlay />
<DevDock enabled={qa} tabs={[networkChaosTab, timewarpTab, a11yLensTab]} />
</NetworkChaos>;- 🧲 One draggable button: shows every active tool's status, e.g.
🛠 flaky · Time warped: 31 Dec - 🗂️ Tabs: each tool brings its own panel
- 🗄️ Storage tab: inspect and edit MMKV, AsyncStorage or localStorage keys on device
- 🧩 Bring your own tool: a tab is a plain object, no dependency on dev-dock needed
- 🎛️ Open from code:
devDock.open('timewarp')from a shake handler or your dev menu - 🪶 Core React Native only: no Reanimated or Gesture Handler peer dependency, about 1.3 kB
- 🚫 Production-safe:
enabled={false}renders nothing, and/noopdrops it from release bundles
import type { DevDockTab } from '@helder-studio/dev-dock';
const featureFlagsTab: DevDockTab = {
id: 'flags',
title: 'Flags',
status: () => (flags.overridden() ? `${flags.overrides().length} flags` : null),
subscribe: flags.subscribe, // optional: refreshes the status
render: () => <FlagsPanel />,
};Search, view, edit and delete stored keys on the phone, with any
@helder-studio/storage adapter (Flipper used to do
this; it's gone from React Native).
import { DevDock, storageTab } from '@helder-studio/dev-dock';
import { mmkv } from '@helder-studio/storage';
const storage = createMMKV();
<DevDock
enabled={qa}
tabs={[storageTab({ storage: mmkv(storage), listKeys: () => storage.getAllKeys() })]}
/>;
// AsyncStorage: storageTab({ storage: asyncStorage(AsyncStorage), listKeys: () => AsyncStorage.getAllKeys() })JSON values are pretty-printed and must stay valid JSON when edited; deleting asks for a second tap.
| Export | What it does |
|---|---|
<DevDock enabled tabs /> |
the button and panel |
devDock.open(tabId?) |
opens the panel, on a tab if given |
devDock.close() |
closes it |
DevDockTab |
{ id, title, status?, subscribe?, render } |
- Web version with a DOM panel
- Remember the button position across restarts
If this saves you time, you can buy me a coffee on Ko-fi. It keeps the helder-studio libraries maintained.