` and the current theme.
+
+5. **Rendering** - The container is a regular `
` element. Your plugin can render anything into it - DOM nodes, a framework component tree via portals, a canvas, an iframe, etc.
+
+6. **Theme changes** - When the user toggles the theme in settings, `render` is called again with the new theme value. Your plugin should update its appearance accordingly.
+
+```mermaid
+flowchart TD
+ A["User opens devtools"] --> B["TanStackDevtoolsCore created
with plugins array"]
+ B --> C["Solid UI renders sidebar
tabs and containers"]
+ C --> D["<h3 id='plugin-title-container-{id}'>
created per plugin"]
+ C --> E["<div id='plugin-container-{id}'>
created per active plugin"]
+ D --> F["plugin.name
string set or function called"]
+ E --> G["plugin.render(div, theme)
called with container + theme"]
+```
+
+## Framework Adapter Pattern
+
+You rarely interact with the raw `TanStackDevtoolsPlugin` interface directly. Instead, each framework adapter converts your familiar component model into the DOM-based plugin contract.
+
+### React / Preact
+
+The React adapter takes your JSX element and uses `createPortal` to render it into the plugin's container element:
+
+```tsx
+// What you write:
+
,
+ }]}
+/>
+
+// What happens internally:
+// The adapter's render function calls:
+// createPortal(
, containerElement)
+```
+
+Your React component runs in its normal React tree with full access to hooks, context, state management, etc. It just renders into a different DOM location via the portal.
+
+### Solid
+
+The Solid adapter uses Solid's `
` component to mount your JSX into the container:
+
+```tsx
+// What you write:
+,
+ }]}
+/>
+
+// What happens internally:
+// The adapter wraps your component in:
+// {yourComponent}
+```
+
+Since the devtools core is itself built in Solid, this is the most native integration. Your component runs inside the same Solid reactive system as the devtools shell.
+
+### Vue
+
+The Vue adapter uses `` to render your Vue component into the container:
+
+```vue
+
+
+
+
+
+
+
+
+```
+
+Your Vue component receives the `theme` as a prop along with any other props you pass. It runs within the Vue app's reactivity system with full access to composition API, inject/provide, etc.
+
+### The Key Insight
+
+```mermaid
+graph LR
+ subgraph fw["Your Framework Runtime"]
+ comp["Your Plugin Component
Full reactivity, hooks, signals"]
+ end
+ subgraph core["Devtools Core (Solid.js)"]
+ container["Plugin Container
<div id='plugin-container-{id}'>"]
+ end
+ comp -- "Portal / Teleport" --> container
+```
+
+Regardless of framework, your plugin component runs in its **normal framework context** with full reactivity, hooks, signals, lifecycle methods, and dependency injection. It just renders into a different DOM location via portals or teleports. This means:
+
+- React plugins can use `useState`, `useEffect`, `useContext`, and any React library.
+- Solid plugins can use signals, stores, `createEffect`, and the full Solid API.
+- Vue plugins can use `ref`, `computed`, `watch`, `inject`, and any Vue composable.
+
+The framework adapter handles all the wiring between your component and the devtools container.
+
+## Plugin State
+
+The devtools persist the active/visible plugin selection in `localStorage` under the key `tanstack_devtools_state`. This means that when a user opens specific plugin tabs, their selection survives page reloads.
+
+Key behaviors:
+
+- **Maximum 3 visible plugins** - At most 3 plugin panels can be displayed simultaneously. Activating a 4th plugin deactivates the earliest one.
+- **`defaultOpen` vs. saved state** - If `defaultOpen: true` is set on a plugin and no saved state exists in localStorage, the plugin opens on first load. Once the user changes the selection, their preference takes precedence.
+- **Single-plugin auto-open** - If only one plugin is registered, it opens automatically regardless of `defaultOpen` or saved state.
+- **Stale plugin cleanup** - When the devtools load, any plugin IDs in the saved state that no longer match a registered plugin are automatically removed.
+
+## Cleanup
+
+When `TanStackDevtoolsCore.unmount()` is called - either explicitly or because the framework component unmounts - the following happens:
+
+1. The Solid reactive system disposes of the entire devtools component tree.
+2. For each active plugin that provides a `destroy` function, `destroy(pluginId)` is called.
+3. All DOM containers created by the core are removed.
+
+Framework adapters handle their own cleanup automatically:
+
+- **React** unmounts the portal, which triggers the normal React cleanup cycle (`useEffect` cleanup functions, etc.).
+- **Vue** destroys the Teleport, which runs `onUnmounted` hooks in your component.
+- **Solid** disposes of the Portal's reactive scope, running any `onCleanup` callbacks.
+
+You typically do **not** need to implement `destroy` unless your plugin has manual subscriptions, timers, WebSocket connections, or other resources that aren't tied to your framework's lifecycle. If all your cleanup is handled by framework hooks (like `useEffect` cleanup in React or `onCleanup` in Solid), the adapter takes care of it for you.
diff --git a/docs/quick-start.md b/docs/quick-start.md
index 2f41aa9a..016c430b 100644
--- a/docs/quick-start.md
+++ b/docs/quick-start.md
@@ -3,81 +3,226 @@ title: Quick Start
id: quick-start
---
-TanStack Devtools is a framework-agnostic devtool for managing and debugging *devtool devtools*
+TanStack Devtools is a framework-agnostic devtool for managing and debugging devtools plugins across React, Preact, Solid, and Vue. Pick your framework below to get started.
-To get up and running install the correct adapter for your framework:
+## React
-- **React**: `npm install @tanstack/react-devtools @tanstack/devtools-vite`
-- **Solid**: `npm install @tanstack/solid-devtools @tanstack/devtools-vite`
+Install the devtools and the Vite plugin:
-Then import the devtools into the root of your application:
+```bash
+npm install @tanstack/react-devtools @tanstack/devtools-vite
+```
+
+Add the `TanStackDevtools` component to the root of your application:
-```javascript
+```tsx
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
import { TanStackDevtools } from '@tanstack/react-devtools'
-function App() {
- return (
- <>
-
-
- >
- )
-}
+import App from './App'
+
+createRoot(document.getElementById('root')!).render(
+
+
+
+ ,
+)
```
-And plug the vite plugin as the first plugin in your plugin array in `vite.config.ts`:
+To add plugins, pass them via the `plugins` prop. Each plugin needs a `name` and a `render` element:
-```javascript
-import { devtools } from '@tanstack/devtools-vite'
+```tsx
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import { TanStackDevtools } from '@tanstack/react-devtools'
+import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
+import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
-export default {
- plugins: [
- devtools(),
- // ... rest of your plugins here
- ],
-}
+import App from './App'
+
+createRoot(document.getElementById('root')!).render(
+
+
+ ,
+ },
+ {
+ name: 'TanStack Router',
+ render: ,
+ },
+ ]}
+ />
+ ,
+)
```
-And you're done! If you want to add custom plugins, you can do so by using the `plugins` prop:
+## Preact
-```javascript
-import { TanStackDevtools } from '@tanstack/react-devtools'
+Install the devtools and the Vite plugin:
-function App() {
- return (
- <>
-
-
- >
- )
-}
+```bash
+npm install @tanstack/preact-devtools @tanstack/devtools-vite
```
-For example, if you want to add TanStack query & router you could do so in the following way:
-```javascript
-import { TanStackDevtools } from '@tanstack/react-devtools'
-import { ReactQueryDevtoolsPanel } from '@tanstack/react-query-devtools'
-import { TanStackRouterDevtoolsPanel } from '@tanstack/react-router-devtools'
+Add the `TanStackDevtools` component using Preact's `render()` function:
+
+```tsx
+import { render } from 'preact'
+import { TanStackDevtools } from '@tanstack/preact-devtools'
+
+import App from './App'
+
+render(
+ <>
+
+
+ >,
+ document.getElementById('root')!,
+)
+```
+
+To add plugins, pass them via the `plugins` prop:
+
+```tsx
+import { render } from 'preact'
+import { TanStackDevtools } from '@tanstack/preact-devtools'
+
+import App from './App'
+
+render(
+ <>
+
+ ,
+ },
+ ]}
+ />
+ >,
+ document.getElementById('root')!,
+)
+```
+
+## Solid
+
+Install the devtools and the Vite plugin:
-function App() {
- return (
-
-
- ...)` pattern:
+
+```tsx
+import { render } from 'solid-js/web'
+import { TanStackDevtools } from '@tanstack/solid-devtools'
+
+import App from './App'
+
+render(() => (
+ <>
+
+
+ >
+), document.getElementById('root')!)
+```
+
+To add plugins, pass them via the `plugins` prop:
+
+```tsx
+import { render } from 'solid-js/web'
+import { TanStackDevtools } from '@tanstack/solid-devtools'
+import { SolidQueryDevtoolsPanel } from '@tanstack/solid-query-devtools'
+import { TanStackRouterDevtoolsPanel } from '@tanstack/solid-router-devtools'
+
+import App from './App'
+
+render(() => (
+ <>
+
+ ,
- defaultOpen: true
+ render: ,
},
{
name: 'TanStack Router',
render: ,
- defaultOpen: false
},
- ]} />
-
- )
+ ]}
+ />
+ >
+), document.getElementById('root')!)
+```
+
+## Vue
+
+Install the Vue devtools adapter:
+
+```bash
+npm install @tanstack/vue-devtools
+```
+
+> The Vite plugin (`@tanstack/devtools-vite`) is optional for Vue but recommended if you want features like enhanced console logs and go-to-source.
+
+Add the `TanStackDevtools` component in your root template:
+
+```vue
+
+
+
+
+
+
+```
+
+To add plugins, define them as an array and pass them via the `:plugins` binding. Vue uses `component` instead of `render` in plugin definitions:
+
+```vue
+
+
+
+
+
+
+```
+
+## Vite Plugin
+
+All frameworks benefit from the optional Vite plugin, which provides enhanced console logs, go-to-source, and a server event bus. Install it as a dev dependency:
+
+```bash
+npm install -D @tanstack/devtools-vite
+```
+
+Add it as the **first** plugin in your Vite config:
+
+```ts
+import { devtools } from '@tanstack/devtools-vite'
+
+export default {
+ plugins: [
+ devtools(),
+ // ... rest of your plugins here
+ ],
}
-```
\ No newline at end of file
+```
+
+For the full list of Vite plugin options, see the [Vite Plugin](./vite-plugin) documentation.
diff --git a/docs/source-inspector.md b/docs/source-inspector.md
new file mode 100644
index 00000000..e49535db
--- /dev/null
+++ b/docs/source-inspector.md
@@ -0,0 +1,86 @@
+---
+title: Source Inspector
+id: source-inspector
+---
+
+The source inspector lets you click any element in your app to open its source file in your editor. When activated, the devtools overlay highlights elements as you hover over them and shows their source file location. Click to open the file at the exact line.
+
+## Requirements
+
+Two things are needed for the source inspector to work:
+
+- The `@tanstack/devtools-vite` plugin must be installed and running (dev server only)
+- Source injection must be enabled: `injectSource.enabled: true` (this is the default)
+
+The feature only works in development. In production builds, source attributes are not injected.
+
+## How It Works
+
+```mermaid
+flowchart LR
+ A["Your JSX/TSX files"] -- "Babel transform" --> B["data-tsd-source
attributes injected"]
+ B -- "Hold inspect hotkey
+ click element" --> C["Devtools reads
data-tsd-source"]
+ C -- "HTTP request" --> D["Vite dev server"]
+ D -- "launch-editor" --> E["Opens file in editor
at exact line"]
+```
+
+The Vite plugin uses Babel to parse your JSX/TSX files during development. It adds a `data-tsd-source="filepath:line:column"` attribute to every JSX element. When you activate the source inspector and click an element, the devtools reads this attribute and sends a request to the Vite dev server. The server then launches your editor at the specified file and line using `launch-editor`.
+
+## Activating the Inspector
+
+There are two ways to activate the source inspector:
+
+- **Hotkey**: Hold Shift+Alt+Ctrl (or Shift+Alt+Meta on Mac) — this is the default `inspectHotkey`. While held, the inspector overlay appears.
+- **Settings panel**: The inspect hotkey can be customized in the devtools Settings tab.
+
+The hotkey can also be configured programmatically:
+
+```ts
+
+```
+
+## Ignoring Files and Components
+
+Not all elements need source attributes. Use the `ignore` config to exclude files or components:
+
+```ts
+import { devtools } from '@tanstack/devtools-vite'
+
+export default {
+ plugins: [
+ devtools({
+ injectSource: {
+ enabled: true,
+ ignore: {
+ files: ['node_modules', /.*\.test\.(js|ts|jsx|tsx)$/],
+ components: ['InternalComponent', /.*Provider$/],
+ },
+ },
+ }),
+ ],
+}
+```
+
+Both `files` and `components` accept arrays of strings (exact match) or RegExp patterns.
+
+## Editor Configuration
+
+Most popular editors work out of the box via the `launch-editor` package. Supported editors include VS Code, WebStorm, Sublime Text, Atom, and more ([full list](https://github.com/yyx990803/launch-editor?tab=readme-ov-file#supported-editors)).
+
+For unsupported editors, use the `editor` config:
+
+```ts
+devtools({
+ editor: {
+ name: 'My Editor',
+ open: async (path, lineNumber, columnNumber) => {
+ const { exec } = await import('node:child_process')
+ exec(`myeditor --goto "${path}:${lineNumber}:${columnNumber}"`)
+ },
+ },
+})
+```
diff --git a/docs/vite-plugin.md b/docs/vite-plugin.md
index cde63117..fa9a4ecb 100644
--- a/docs/vite-plugin.md
+++ b/docs/vite-plugin.md
@@ -204,13 +204,47 @@ export default {
## Features
-### Go to source
+The Vite plugin is composed of several sub-plugins, each handling a specific concern:
+
+```mermaid
+graph TD
+ vite["@tanstack/devtools-vite"]
+ vite --> source["Source Injection
Babel → data-tsd-source attrs"]
+ vite --> server["Server Event Bus
WebSocket + SSE transport"]
+ vite --> strip["Production Stripping
Remove devtools on build"]
+ vite --> pipe["Console Piping
Client ↔ Server logs"]
+ vite --> logs["Enhanced Logs
Source location in console"]
+ vite --> market["Marketplace
Install plugins via UI"]
+ vite --> connect["Connection Injection
Port/host placeholders"]
+```
+
+### Go to Source
+
+The "Go to Source" feature lets you click on any element in your browser and open its source file in your editor at the exact line where it's defined. It works by injecting `data-tsd-source` attributes into your components via a Babel transformation during development. These attributes encode the file path and line number of each element.
+
+To use it, activate the source inspector by holding the inspect hotkey (default: Shift+Alt+Ctrl/Meta). An overlay will highlight elements under your cursor and display their source location. Clicking on a highlighted element opens the corresponding file in your editor at the exact line, powered by `launch-editor` under the hood.
+
+For a complete guide on configuration and usage, see the [Source Inspector](./source-inspector) docs.
+
+### Console Piping
+
+When enabled (default), `console.log()` and other console methods in the browser are piped to your terminal, and server-side console output appears in the browser console. This is particularly useful when debugging SSR or API routes — you see all logs in one place without switching between terminal and browser. Configure which log levels are piped via `consolePiping.levels`.
+
+### Enhanced Logs
+
+Console logs are enhanced with clickable source locations. In the browser console, each log shows the file and line number where it originated. Click to open the source file in your editor. Enable/disable via the `enhancedLogs` config option.
+
+### Production Build Stripping
-Allows you to open the source location on anything in your browser by clicking on it.
+By default (`removeDevtoolsOnBuild: true`), the Vite plugin replaces all devtools imports with empty modules in production builds. This includes:
+- `@tanstack/react-devtools`
+- `@tanstack/vue-devtools`
+- `@tanstack/solid-devtools`
+- `@tanstack/preact-devtools`
+- `@tanstack/devtools`
-To trigger this behavior you need the Devtools Vite plugin installed and configured and
-the Panel available on the page. Simply click on any element while holding down the Shift and Ctrl (or Meta) keys.
+This ensures zero devtools code reaches production. Set `removeDevtoolsOnBuild: false` to keep devtools in production (see [Production](./production) docs).
-### Advanced console logs
+### Plugin Marketplace
-Allows you to go directly to the console log location directly from the browser/terminal
+The Vite plugin enables the in-devtools plugin marketplace. When you browse available plugins in the devtools Settings tab and click "Install", the Vite plugin handles the npm/pnpm/yarn installation and automatically injects the plugin import into your devtools setup file. This only works during development with the Vite dev server running.