| name | create-table-hook |
| description | Share TanStack Ember Table v9 features, row-model slots, defaults, and inferred column helpers with createTableHook, createAppTable, createAppColumnHelper, and appFeatures. Load for recurring Ember table conventions, per-table overrides, or confusion with component/context registries from other adapters.
|
| metadata | {"type":"framework","library":"@tanstack/ember-table","framework":"ember","library_version":"9.2.4"} |
| requires | ["@tanstack/table-core#core","getting-started","table-state"] |
| sources | ["TanStack/table:docs/framework/ember/guide/composable-tables.md","TanStack/table:examples/ember/basic-app-table","TanStack/table:packages/ember-table/src/create-table-hook.ts"] |
This skill builds on @tanstack/table-core#core, getting-started, and table-state. Use an app factory when several tables share real features or defaults; keep a one-off table on useTable.
Setup
import Component from '@glimmer/component'
import { tracked } from '@glimmer/tracking'
import {
createSortedRowModel,
createTableHook,
rowSortingFeature,
sortFn_alphanumeric,
tableFeatures,
} from '@tanstack/ember-table'
const features = tableFeatures({
rowSortingFeature,
sortedRowModel: createSortedRowModel(),
sortFns: { alphanumeric: sortFn_alphanumeric },
})
export const { appFeatures, createAppColumnHelper, createAppTable } =
createTableHook({
features,
enableSortingRemoval: false,
})
type Person = { id: string; name: string }
const columnHelper = createAppColumnHelper<Person>()
const columns = columnHelper.columns([
columnHelper.accessor('name', { header: 'Name' }),
])
export default class PeopleTable extends Component {
@tracked data: Person[] = []
table = createAppTable(() => ({
columns,
data: this.data,
}))
}
Create the hook and column helpers at stable module scope. createAppTable preserves the useTable options thunk, so tracked reads such as this.data remain reactive. Do not pass features again at the table call site; the factory owns the feature set and binds it into column inference.
Composition Contract
- Hook options supply stable shared
features and default table options.
createAppColumnHelper<TData>() binds the feature type while inferring each row type.
createAppTable(() => options) merges shared defaults with table-specific options.
- Table-specific options win over shared defaults, except that the factory remains the feature owner.
appFeatures exposes the exact registered feature set for helper types or reusable utilities.
Shared options intentionally exclude columns, data, and state. Keep model inputs and controlled state at each table call site; share conventions, not one mutable state object across unrelated tables.
Sharing rowSortingFeature, sortedRowModel, and sorting defaults gives every table sorting capability; it does not make their internal sorting state shared. The factory technically accepts a stable external atom in shared atoms, but that deliberately couples tables and their column IDs. Prefer independent state unless synchronized tables are the actual product behavior.
Render Normally
Ember's factory does not register AppTable, AppCell, AppHeader, context hooks, or reusable component registries. Continue rendering with FlexRenderCell, FlexRenderHeader, and FlexRenderFooter. Continue wrapping receiver-dependent v9 methods in Ember template helpers as described by getting-started.
Common Mistakes
HIGH Copying another adapter's component registry
Wrong: expect table.AppTable, useTableContext, or a tableComponents option from React, Solid, Svelte, or Lit examples.
Correct: use the normal Ember FlexRender components and pass the table through ordinary Ember composition when another component truly needs it.
The Ember hook shares features/defaults and type inference only.
HIGH Passing features per table
Wrong:
createAppTable(() => ({ features: otherFeatures, columns, data: this.data }))
Correct: define a separate app hook when a table needs a genuinely different feature set. createAppTable omits features from its call-site type.
HIGH Recreating the hook or columns with tracked updates
Wrong: call createTableHook, createAppColumnHelper, or columns(...) inside a component getter or the createAppTable thunk.
Correct: create them once at module scope and let the table thunk read only changing inputs.
MEDIUM Sharing controlled state as a default
The hook options omit state. Put state and matching on[State]Change callbacks in each createAppTable thunk so every table has one clear owner per slice. Use a shared external atom only when tables intentionally coordinate the same compatible slice.
MEDIUM Repeating manual feature generics
Use createAppColumnHelper<Person>(); do not thread typeof features through every column helper after the factory has already captured it.
API Discovery
Inspect node_modules/@tanstack/ember-table/declarations/create-table-hook.d.ts for the installed factory return shape, omitted options, and merge precedence. Inspect use-table.d.ts for thunk reactivity and node_modules/@tanstack/table-core/dist/features/<feature>/ for the shared feature APIs. Do not infer Ember component/context behavior from another adapter's createTableHook.