Docs
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
CodeRabbit
Cloudflare
AG Grid
SerpAPI
Netlify
OpenRouter
WorkOS
Clerk
Electric
PowerSync
Sentry
Railway
Prisma
Strapi
Unkey
Table API Reference
Column API Reference
Row API Reference
Cell API Reference
Header API Reference
Features API Reference
Static Functions API Reference
Table API Reference

createTableHook

Function: createTableHook()

ts
function createTableHook<TFeatures, TTableComponents, TCellComponents, THeaderComponents>(__namedParameters): object;
function createTableHook<TFeatures, TTableComponents, TCellComponents, THeaderComponents>(__namedParameters): object;

Defined in: createTableHook.ts:427

Creates a custom table hook with pre-bound components for composition.

This is the table equivalent of TanStack Form's createFormHook. It allows you to:

  • Define features, row models, and default options once, shared across all tables
  • Register reusable table, cell, and header components
  • Access table/cell/header instances via @lit/context in those components
  • Get a useAppTable hook that returns an extended table with App wrapper functions
  • Get a createAppColumnHelper function pre-bound to your features

Type Parameters

TFeatures

TFeatures extends TableFeatures

TTableComponents

TTableComponents extends Record<string, ComponentType<any>>

TCellComponents

TCellComponents extends Record<string, ComponentType<any>>

THeaderComponents

THeaderComponents extends Record<string, ComponentType<any>>

Parameters

__namedParameters

CreateTableHookOptions<TFeatures, TTableComponents, TCellComponents, THeaderComponents>

Returns

appFeatures

ts
appFeatures: TFeatures;
appFeatures: TFeatures;

createAppColumnHelper()

ts
createAppColumnHelper: <TData>() => AppColumnHelper<TFeatures, TData, TCellComponents, THeaderComponents>;
createAppColumnHelper: <TData>() => AppColumnHelper<TFeatures, TData, TCellComponents, THeaderComponents>;

Create a column helper pre-bound to the features and components configured in this table hook. The cell, header, and footer contexts include pre-bound components (e.g., cell.TextCell).

Type Parameters

TData

TData extends RowData

Returns

AppColumnHelper<TFeatures, TData, TCellComponents, THeaderComponents>

Example

ts
const columnHelper = createAppColumnHelper<Person>()

const columns = [
  columnHelper.accessor('firstName', {
    header: 'First Name',
    cell: ({ cell }) => cell.FlexRender(), // cell has pre-bound components!
  }),
  columnHelper.accessor('age', {
    header: 'Age',
    cell: ({ cell }) => cell.NumberCell(),
  }),
]
const columnHelper = createAppColumnHelper<Person>()

const columns = [
  columnHelper.accessor('firstName', {
    header: 'First Name',
    cell: ({ cell }) => cell.FlexRender(), // cell has pre-bound components!
  }),
  columnHelper.accessor('age', {
    header: 'Age',
    cell: ({ cell }) => cell.NumberCell(),
  }),
]

useAppTable()

ts
useAppTable: <TData, TSelected>(host, tableOptions, selector?) => object;
useAppTable: <TData, TSelected>(host, tableOptions, selector?) => object;

Enhanced table hook that returns a controller-like object with a table() method. The returned table has App wrapper functions and pre-bound tableComponents attached directly to the table object.

Default options from createTableHook are automatically merged with the options passed here. Options passed here take precedence.

TFeatures is already known from the createTableHook call; TData is inferred from the data prop.

Type Parameters

TData

TData extends RowData

TSelected

TSelected = TableState<TFeatures>

Parameters

host

ReactiveControllerHost & HTMLElement

tableOptions

Omit<TableOptions<TFeatures, TData>, "_features" | "_rowModels">

selector?

(state) => TSelected

Returns

object

table()
ts
table: () => AppLitTable<TFeatures, TData, TSelected, TTableComponents, TCellComponents, THeaderComponents>;
table: () => AppLitTable<TFeatures, TData, TSelected, TTableComponents, TCellComponents, THeaderComponents>;
Returns

AppLitTable<TFeatures, TData, TSelected, TTableComponents, TCellComponents, THeaderComponents>

Example

ts
@customElement('my-table')
class MyTable extends LitElement {
  private appTable = useAppTable(this, {
    columns,
    data: this.data,
  })

  protected render() {
    const table = this.appTable.table()
    return html`...`
  }
}
@customElement('my-table')
class MyTable extends LitElement {
  private appTable = useAppTable(this, {
    columns,
    data: this.data,
  })

  protected render() {
    const table = this.appTable.table()
    return html`...`
  }
}

useCellContext()

ts
useCellContext: <TValue>(host) => ContextConsumer<Context<symbol, Cell<TFeatures, any, TValue>>, ReactiveControllerHost & HTMLElement>;
useCellContext: <TValue>(host) => ContextConsumer<Context<symbol, Cell<TFeatures, any, TValue>>, ReactiveControllerHost & HTMLElement>;

Access the cell instance from within a custom element that is a descendant of an element providing cell context. Uses @lit/context ContextConsumer to retrieve the cell. TFeatures is already known from the createTableHook call.

Type Parameters

TValue

TValue extends unknown = unknown

Parameters

host

ReactiveControllerHost & HTMLElement

Returns

ContextConsumer<Context<symbol, Cell<TFeatures, any, TValue>>, ReactiveControllerHost & HTMLElement>

Example

ts
@customElement('text-cell')
class TextCell extends LitElement {
  private _cell = useCellContext(this)

  protected render() {
    const cell = this._cell.value
    if (!cell) return html``
    return html`<span>${cell.getValue()}</span>`
  }
}
@customElement('text-cell')
class TextCell extends LitElement {
  private _cell = useCellContext(this)

  protected render() {
    const cell = this._cell.value
    if (!cell) return html``
    return html`<span>${cell.getValue()}</span>`
  }
}

useHeaderContext()

ts
useHeaderContext: <TValue>(host) => ContextConsumer<Context<symbol, Header<TFeatures, any, TValue>>, ReactiveControllerHost & HTMLElement>;
useHeaderContext: <TValue>(host) => ContextConsumer<Context<symbol, Header<TFeatures, any, TValue>>, ReactiveControllerHost & HTMLElement>;

Access the header instance from within a custom element that is a descendant of an element providing header context. Uses @lit/context ContextConsumer to retrieve the header. TFeatures is already known from the createTableHook call.

Type Parameters

TValue

TValue extends unknown = unknown

Parameters

host

ReactiveControllerHost & HTMLElement

Returns

ContextConsumer<Context<symbol, Header<TFeatures, any, TValue>>, ReactiveControllerHost & HTMLElement>

Example

ts
@customElement('sort-indicator')
class SortIndicator extends LitElement {
  private _header = useHeaderContext(this)

  protected render() {
    const header = this._header.value
    if (!header) return html``
    const sorted = header.column.getIsSorted()
    return html`${sorted === 'asc' ? '🔼' : sorted === 'desc' ? '🔽' : ''}`
  }
}
@customElement('sort-indicator')
class SortIndicator extends LitElement {
  private _header = useHeaderContext(this)

  protected render() {
    const header = this._header.value
    if (!header) return html``
    const sorted = header.column.getIsSorted()
    return html`${sorted === 'asc' ? '🔼' : sorted === 'desc' ? '🔽' : ''}`
  }
}

useTableContext()

ts
useTableContext: <TData>(host) => ContextConsumer<Context<symbol, LitTable<TFeatures, TData, any>>, ReactiveControllerHost & HTMLElement>;
useTableContext: <TData>(host) => ContextConsumer<Context<symbol, LitTable<TFeatures, TData, any>>, ReactiveControllerHost & HTMLElement>;

Access the table instance from within a custom element that is a descendant of the element using useAppTable. Uses @lit/context ContextConsumer to retrieve the table from the nearest ancestor provider. TFeatures is already known from the createTableHook call.

Type Parameters

TData

TData extends RowData = RowData

Parameters

host

ReactiveControllerHost & HTMLElement

Returns

ContextConsumer<Context<symbol, LitTable<TFeatures, TData, any>>, ReactiveControllerHost & HTMLElement>

Example

ts
@customElement('pagination-controls')
class PaginationControls extends LitElement {
  private _table = useTableContext(this)

  protected render() {
    const table = this._table.value
    if (!table) return html``
    return html`
      <button @click=${() => table.previousPage()}>Prev</button>
      <button @click=${() => table.nextPage()}>Next</button>
    `
  }
}
@customElement('pagination-controls')
class PaginationControls extends LitElement {
  private _table = useTableContext(this)

  protected render() {
    const table = this._table.value
    if (!table) return html``
    return html`
      <button @click=${() => table.previousPage()}>Prev</button>
      <button @click=${() => table.nextPage()}>Next</button>
    `
  }
}

Example

ts
// hooks/table.ts
export const {
  createAppColumnHelper,
  useAppTable,
  useTableContext,
  useCellContext,
  useHeaderContext,
} = createTableHook({
  _features: tableFeatures({
    rowPaginationFeature,
    rowSortingFeature,
    columnFilteringFeature,
  }),
  _rowModels: {
    paginatedRowModel: createPaginatedRowModel(),
    sortedRowModel: createSortedRowModel(sortFns),
    filteredRowModel: createFilteredRowModel(filterFns),
  },
  tableComponents: { PaginationControls, RowCount },
  cellComponents: { TextCell, NumberCell },
  headerComponents: { SortIndicator, ColumnFilter },
})

// Create column helper with TFeatures already bound
const columnHelper = createAppColumnHelper<Person>()

// my-table.ts
@customElement('my-table')
class MyTable extends LitElement {
  private appTable = useAppTable(this, {
    columns,
    data: this.data,
  })

  protected render() {
    const table = this.appTable.table()

    return html`
      <table>
        <thead>
          ${repeat(table.getHeaderGroups(), (hg) => hg.id, (hg) => html`
            <tr>
              ${hg.headers.map((h) => table.AppHeader(h, (header) => html`
                <th>${header.FlexRender()}</th>
              `))}
            </tr>
          `)}
        </thead>
        <tbody>
          ${table.getRowModel().rows.map((row) => html`
            <tr>
              ${row.getAllCells().map((c) => table.AppCell(c, (cell) => html`
                <td>${cell.FlexRender()}</td>
              `))}
            </tr>
          `)}
        </tbody>
      </table>
    `
  }
}
// hooks/table.ts
export const {
  createAppColumnHelper,
  useAppTable,
  useTableContext,
  useCellContext,
  useHeaderContext,
} = createTableHook({
  _features: tableFeatures({
    rowPaginationFeature,
    rowSortingFeature,
    columnFilteringFeature,
  }),
  _rowModels: {
    paginatedRowModel: createPaginatedRowModel(),
    sortedRowModel: createSortedRowModel(sortFns),
    filteredRowModel: createFilteredRowModel(filterFns),
  },
  tableComponents: { PaginationControls, RowCount },
  cellComponents: { TextCell, NumberCell },
  headerComponents: { SortIndicator, ColumnFilter },
})

// Create column helper with TFeatures already bound
const columnHelper = createAppColumnHelper<Person>()

// my-table.ts
@customElement('my-table')
class MyTable extends LitElement {
  private appTable = useAppTable(this, {
    columns,
    data: this.data,
  })

  protected render() {
    const table = this.appTable.table()

    return html`
      <table>
        <thead>
          ${repeat(table.getHeaderGroups(), (hg) => hg.id, (hg) => html`
            <tr>
              ${hg.headers.map((h) => table.AppHeader(h, (header) => html`
                <th>${header.FlexRender()}</th>
              `))}
            </tr>
          `)}
        </thead>
        <tbody>
          ${table.getRowModel().rows.map((row) => html`
            <tr>
              ${row.getAllCells().map((c) => table.AppCell(c, (cell) => html`
                <td>${cell.FlexRender()}</td>
              `))}
            </tr>
          `)}
        </tbody>
      </table>
    `
  }
}