getting-started

SkillWeb & browsing

Guides your agent through building a working TanStack React Table v9 component with correct hooks and rendering.

Available today. Use it from your connected AI after setup.

Add ahel to your AI once: Claude, ChatGPT, Cursor, Claude Code or Codex. Then ask it to use this.

Then ask your AI: use the getting-started skill

About this skill

Create and render a TanStack React Table v9 table with useTable, tableFeatures, stable data and columns, row/header models, and table.FlexRender. Load for a first React table, headless rendering, or when v8 useReactTable examples are producing the wrong setup.

What this skill tells your AI

The instructions your AI receives, as published by octanejs/octane in packages/tanstack-table/upstream/skills/getting-started/SKILL.md and read by ahel’s review.

This skill builds on @tanstack/table-core#core and @tanstack/table-core#table-features. Read them first for the headless model and explicit feature registration.

Setup

import { useMemo, useState } from 'react'
import {
  createColumnHelper,
  tableFeatures,
  useTable,
} from '@tanstack/react-table'

type Person = { name: string; age: number }
const features = tableFeatures({})
const helper = createColumnHelper<typeof features, Person>()
const columns = helper.columns([
  helper.accessor('name', { header: 'Name' }),
  helper.accessor('age', { header: 'Age' }),
])

export function PeopleTable() {
  const [data] = useState<Person[]>([{ name: 'Ada', age: 36 }])
  const table = useTable({ features, columns, data })

  return (
    <table>
      <thead>
        {table.getHeaderGroups().map((group) => (
          <tr key={group.id}>
            {group.headers.map((header) => (
              <th key={header.id}>
                {header.isPlaceholder ? null : (
                  <table.FlexRender header={header} />
                )}
              </th>
            ))}
          </tr>
        ))}
      </thead>
      <tbody>
        {table.getRowModel().rows.map((row) => (
          <tr key={row.id}>
            {row.getAllCells().map((cell) => (
              <td key={cell.id}>
                <table.FlexRender cell={cell} />
              </td>
            ))}
          </tr>
        ))}
      </tbody>
    </table>
  )
}

Table produces models and state; React owns the semantic markup, styles, event affordances, and accessibility.

Core Patterns

Add only the feature the table uses

import {
  createSortedRowModel,
  rowSortingFeature,
  tableFeatures,
} from '@tanstack/react-table'

const sortableFeatures = tableFeatures({
  rowSortingFeature,
  sortedRowModel: createSortedRowModel(),
})

Row-model slots belong inside tableFeatures, after their prerequisite feature.

Keep static inputs outside render

const features = tableFeatures({})
const data: Person[] = [{ name: 'Ada', age: 36 }]

Use state, memoization, or query results for changing data; avoid a new fallback array every render.

Common Mistakes

HIGH Copying the v8 table constructor

Wrong:

const table = useReactTable({
  data,
  columns,
  getCoreRowModel: getCoreRowModel(),
})

Correct:

const table = useTable({ data, columns, features })

V9 uses useTable; optional row models are registered as feature slots rather than table options.

Source: docs/framework/react/guide/migrating.md

HIGH Assuming feature APIs are global

Wrong:

const features = tableFeatures({})

Correct:

const features = tableFeatures({
  rowSortingFeature,
  sortedRowModel: createSortedRowModel(),
})

Sorting state and methods do not exist until the sorting feature is registered.

Source: packages/table-core/src/TableFeatures.ts

MEDIUM Recreating fallback data each render

Wrong:

const table = useTable({ features, columns, data: response.data ?? [] })

Correct:

// module scope
const EMPTY_DATA: Person[] = []
const table = useTable({ features, columns, data: response.data ?? EMPTY_DATA })

A fresh fallback invalidates data-dependent models on every render.

Source: docs/framework/react/guide/data.md

API Discovery

Inspect node_modules/@tanstack/react-table/dist/index.d.ts first, then the exported useTable.d.ts, FlexRender.d.ts, or core feature source. Use installed declarations so names match the consumer's exact v9 version.

Signals

GitHub stars
1k
Forks
56
Last commit
Sep 2026
Advanced
Item type
skill
Key
getting-started-octanejs
Source
github.com/octanejs/octane
getting-started by octanejs: Skill · ahel