# Tanstack Table Vue Compose With Tanstack Devtools

> This skill builds on `tanstack-table/vue/table-state`. Read that first — the devtools panel inspects whatever table instance you register, so you need a working `useTable` before this skill is useful.

- Skill: `tomevault-io/tanstack-table-vue-compose-with-tanstack-devtools` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add tomevault-io/tanstack-table-vue-compose-with-tanstack-devtools`
- Raw SKILL.md: https://api.skillmd.com/api/skills/tomevault-io/tanstack-table-vue-compose-with-tanstack-devtools/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: tomevault-io (https://skillmd.com/u/tomevault-io)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/tomevault-io/tanstack-table-vue-compose-with-tanstack-devtools

---


This skill builds on `tanstack-table/vue/table-state`. Read that first — the devtools panel inspects whatever table instance you register, so you need a working `useTable` before this skill is useful.

## Setup

Install the TanStack Devtools host and the Vue Table adapter:

```sh
pnpm add @tanstack/vue-devtools @tanstack/vue-table-devtools
```

The recommended pattern has two parts:

1. Mount `TanStackDevtools` once at the app root with `tableDevtoolsPlugin()`.
2. Call `useTanStackTableDevtools(table, name?)` inside `<script setup>` after each `useTable()`.

### App Root (`main.ts`)

```ts
import { createApp, defineComponent, h } from 'vue'
import { TanStackDevtools } from '@tanstack/vue-devtools'
import { tableDevtoolsPlugin } from '@tanstack/vue-table-devtools'
import App from './App.vue'

const Root = defineComponent({
  setup() {
    return () => [
      h(App),
      h(TanStackDevtools, {
        plugins: [tableDevtoolsPlugin()],
      }),
    ]
  },
})

createApp(Root).mount('#app')
```

### Component (`UsersScreen.vue`)

```vue
<script setup lang="ts">
import { useTable } from '@tanstack/vue-table'
import { useTanStackTableDevtools } from '@tanstack/vue-table-devtools'

const table = useTable({
  _features,
  _rowModels,
  columns,
  data,
})

useTanStackTableDevtools(table, 'Users Table')
</script>

<template>
  <UsersGrid :table="table" />
</template>
```

`tableDevtoolsPlugin()` returns a plugin descriptor for the multi-panel TanStack Devtools UI. `useTanStackTableDevtools` is a Vue composable that registers/unregisters the table via a `watchEffect`, so it reacts to `MaybeRef` inputs for the table, name, and `enabled` option.

## Patterns

### Naming Tables

The optional second argument labels the table in the panel selector. Without it, devtools assign fallback names like `Table 1` and `Table 2`.

```ts
useTanStackTableDevtools(table, 'Orders Table')
```

The name may be reactive — pass a `Ref<string>` to update the label live.

### Multiple Tables

Register multiple tables and the Table panel renders a selector. Name each one.

```vue
<script setup lang="ts">
const ordersTable = useTable(ordersOptions)
const usersTable = useTable(usersOptions)

useTanStackTableDevtools(ordersTable, 'Orders')
useTanStackTableDevtools(usersTable, 'Users')
</script>
```

### Disabling Per Table

`useTanStackTableDevtools` accepts an `enabled` option (reactive). When `false`, the registration is removed but the composable runs cleanly.

```ts
import { ref } from 'vue'
const showTableDevtools = ref(false)

useTanStackTableDevtools(table, 'Users Table', {
  enabled: showTableDevtools.value,
})
```

### Production Builds

The default `@tanstack/vue-table-devtools` entrypoint swaps to no-op implementations when `process.env.NODE_ENV !== 'development'`. To ship the real devtools to production, switch BOTH imports to the `/production` entrypoint:

```ts
// main.ts
import { tableDevtoolsPlugin } from '@tanstack/vue-table-devtools/production'
```

```vue
<script setup lang="ts">
import { useTanStackTableDevtools } from '@tanstack/vue-table-devtools/production'
</script>
```

If you mix entrypoints (one from `/production`, one from the default), one side is a no-op in production and the panel will appear empty.

### Conditional Devtools by Env

A common pattern is to dynamically import the production entrypoint behind a feature flag:

```ts
import { defineAsyncComponent } from 'vue'

const TableDevtoolsRoot = defineAsyncComponent(async () => {
  const { tableDevtoolsPlugin } =
    await import('@tanstack/vue-table-devtools/production')
  const { TanStackDevtools } = await import('@tanstack/vue-devtools')
  return {
    setup() {
      return () => h(TanStackDevtools, { plugins: [tableDevtoolsPlugin()] })
    },
  }
})
```

## Common Mistakes

### Forgetting to mount `TanStackDevtools` at the app root

Calling `useTanStackTableDevtools(table)` alone does nothing visible — it only registers the table with the devtools target store. Without a `<TanStackDevtools :plugins="[tableDevtoolsPlugin()]" />` (or `h(TanStackDevtools, ...)`) somewhere in the tree, there is no panel to render the registration. Symptom: composable runs without errors, no devtools button appears.

### Importing devtools from the default path in a prod-only bundle

If you only deploy production builds, `@tanstack/vue-table-devtools` resolves to no-op implementations. The plugin will mount, but the panel will be empty. Use `@tanstack/vue-table-devtools/production` if you want the real devtools available there.

### Accidentally shipping devtools to end users via `/production`

The flip side: importing from `/production` in your default app bundle means every visitor downloads and runs the devtools UI. That is usually not what you want. Restrict `/production` imports to dev/preview entrypoints or code-split them behind a flag.

### Calling `useTanStackTableDevtools` outside `setup`

The composable uses `watchEffect` and `getCurrentInstance` — it must run inside a component's `setup` / `<script setup>` block. Calling it in a regular utility function gives an unstable registration id and no automatic cleanup.

### Multiple tables without names

Two `useTanStackTableDevtools(table)` calls without a name produce selector entries like `Table 1` / `Table 2`. When you have 3+ tables this becomes unusable. Always pass a descriptive name as the second argument.

---
> Source: [TanStack/table](https://github.com/TanStack/table) — distributed by [TomeVault](https://tomevault.io).
<!-- tomevault:4.0:skill_md:2026-05-24 -->

