pgTable/API Reference/pgt.tableColumns
API ReferenceHelper

pgt.tableColumns

The column-shape declaration helper. The two-call form — pgt.tableColumns<Meta>()(columns) — pins a Meta generic for your column-meta-type while preserving the exact column shape on the return value, so PgTableRow infers cleanly downstream.

Signature

The first call binds the Meta generic — the column-meta-type your render-components consume (label, sortable, align, etc.). The second call captures the columns object literal and returns it unchanged: pgTable does not transform it, it just narrows the type.

TSsignature.ts
// signature
pgt.tableColumns<Meta = {}>()(columns: Record<string, { type: z.ZodType } & Meta>)
// returns the same object, narrowed to the exact input shape

Simple-table usage

In a simple-table the table-config lives inline in the <name>-table.tsx file. Each column needs at least a type field carrying a Zod schema; the row type is derived from those schemas through PgTableRow<typeof columns>.

TScharacters-table.tsx
import z from 'zod'
import { pgt } from '@westopp/pgtable'

const charactersColumns = pgt.tableColumns()({
id:    { type: z.string() },
name:  { type: z.string() },
power: { type: z.number() },
})

// PgTableRow<typeof charactersColumns> is { id: string; name: string; power: number }

With a column-meta-type

The Meta generic is your contract with your own render-components. Add label, sortable, align, hidden, an icon name, a cell type — whatever your headers and cells want to read off columnInfo. pgTable hands the object back unchanged; the column-meta-type is yours.

TSXcharacters-table-config.ts
// Moderate-table config: column-meta-type pinned via the generic.
// pgTable does not read these fields — your render-components do.
import z from 'zod'
import { pgt } from '@westopp/pgtable'

type CharacterColumnMeta = {
label: string
sortable?: boolean
align?: 'left' | 'right'
hidden?: boolean
}

export const charactersColumns = pgt.tableColumns<CharacterColumnMeta>()({
id:     { type: z.string(),                                label: 'ID',     hidden: true },
name:   { type: z.string(),                                label: 'Name',   sortable: true },
power:  { type: z.number(),                                label: 'Power',  sortable: true, align: 'right' },
status: { type: z.enum(['active', 'dormant', 'fallen']),   label: 'Status', sortable: true },
})

Consuming columns in a render-component

tableApi.getColumnsArray() walks the columns in declaration order and gives you { columnName, columnInfo } entries. A render-component takes these via props and casts columnInfo to its column-meta-type at the read site.

TSXcharacters-table-headers.tsx
// Render-component: function of its props, no hooks, no globals.
// Headers come from tableApi.getColumnsArray() in the composition-component
// above and arrive here as an already-walked array.
type HeaderProps = {
columns: { columnName: string; columnInfo: CharacterColumnMeta & { type: unknown } }[]
}

export const CharactersTableHeaders = ({ columns }: HeaderProps) => (
<tr>
  {columns
    .filter((c) => !c.columnInfo.hidden)
    .map((c) => (
      <th key={c.columnName} style={{ textAlign: c.columnInfo.align ?? 'left' }}>
        {c.columnInfo.label}
      </th>
    ))}
</tr>
)

Sharing columns via a column-registry

When the same column definition appears in two or more table-configs with the same semantic meaning — id, createdAt, an actions cell — hoist it to a column-registry and spread it back in. pgt.columnRegistry<Meta>()({...}) is generic over the same Meta as the consuming tableColumns call, so the column-meta-type stays consistent across every table that reuses it.

TStables/shared/shared-table-configs.ts
// Shared building blocks live in tables/shared/. A single-use column stays
// inline in its table-config; the registry is for what is actually reused.
import z from 'zod'
import { pgt } from '@westopp/pgtable'

export type SharedColumnMeta = {
label: string
sortable: boolean
align?: 'left' | 'right'
hidden?: boolean
}

export const sharedColumnRegistry = pgt.columnRegistry<SharedColumnMeta>()({
id:        { type: z.string(), label: 'ID',      sortable: false, hidden: true },
createdAt: { type: z.string(), label: 'Created', sortable: true },
updatedAt: { type: z.string(), label: 'Updated', sortable: true },
})