0%
balqalam Logo
balqalam
FeaturesCommunityPricingDocumentation
Login
  • Introduction
  • Pitch
  • Hogwarts
  • Live Demo
  • MVP
  • Roadmap
  • Launch Sprint
  • PRD
  • Get Started
  • Localhost
  • Architecture
  • Structure
  • Pattern
  • Page
  • Layout
  • Content
  • Types
  • Config
  • Actions
  • Queries
  • Authorization
  • Validation
  • Form
  • Table
  • Detail
  • Card
  • Util
  • Hooks
  • List Params
  • Views
  • README.md
  • ISSUE.md
  • Technology Stack
  • Database
  • File
  • CDN Assets
  • Entry Points
  • Dashboard
  • Authentication
  • Credentials
  • OAuth
  • Flow Diagrams
  • Multi-Tenancy
  • Offline
  • Onboarding
  • Onboarding Videos
  • Add Values
  • Admission
  • Application
  • Attendance
  • Compliance
  • Profile
  • Exams
  • Exam Wizard
  • Timetable
  • Classrooms
  • Notifications
  • Conference
  • LMS (Lumos)
Finance
  • Finance
  • Fee Management
  • Invoice
  • Wallet
  • Salary
  • Payroll
  • Timesheet
  • Expenses
  • Budget
  • Receipt
  • Accounts
  • Banking
  • Reports
  • Dashboard
  • Permissions
  • Messages
  • Integration Flow
  • Provision
  • AI Document Processing
  • Document Intelligence
  • Internationalization
  • Translation
  • Translation Guide
  • Icons
  • Docs Factory
  • Inspiration
  • Listings
  • Teachers
  • Students
  • Catalog
  • Library
  • Contributing
  • Code of conduct
  • GitHub Workflow
  • Database Seeds
  • Database Safety
  • Test Accounts
  • Playwright
  • Prettier
  • Block Rebound
Sales & GTM
  • Marketing Brief
  • Sales
  • Go-to-market
  • Marketing
  • Admission — Feature Spotlight
  • Pilot Program
  • Leads
  • Proposal
  • Outreach Templates
  • Case Study
  • Competitors
  • Landing-page teardown
  • Competitor FAQ
  • Business model
  • Shared economy
  • Traction
Fundraising & Ecosystem
  • Get Support
  • Investor Deck
  • Data Room
  • Investors
  • Accelerators
  • Incubators
  • Grants
  • Sponsors
  • Partners
  • Competitions & Hackathons
  • Universities & Training Centers

Table

PreviousNext

DataTable wrapper plus column definitions for a feature.

table.tsx and columns.tsx are client leaves rendered by client.tsx. Both are always "use client" — TanStack Table requires hooks and cells use JSX. Data is fetched on the server and passed in as props.

Categories — columns.tsx

CategoryShapeReference
Factory with callbacks (newer, preferred)get<Entity>Columns(dictionary, lang, callbacks)listings/teachers/columns.tsx
Factory with useModal in cells (legacy)Hook inside cell renderer (anti-pattern)listings/students/columns.tsx
Static arrayconst <entity>Columns: ColumnDef<RowType>[]saas-dashboard/domains/columns.tsx

Categories — table.tsx

CategoryShapeReference
DataTable + load-moreuseDataTable with paginationMode="load-more"saas-dashboard/domains/table.tsx
DataTable + paginationURL-based pagination via nuqslistings/teachers/table.tsx
Raw shadcn <Table>Simple non-interactive displaysbilling/invoice-table.tsx

Rules

#Rule
1"use client" for both files
2Row types in types.ts, never inline in columns.tsx
3Use callback pattern for actions — never call hooks inside cell renderers
4useMemo for column generation in table.tsx
5Use the shared DataTable + useDataTable from @/components/table/
6Stay under ~200 lines per file

Canonical example — minimal table

"use client"
 
import { useMemo } from "react"
 
import { DataTable } from "@/components/table/data-table"
import { useDataTable } from "@/components/table/use-data-table"
 
import { catalogColumns, type CatalogSubjectRow } from "./columns"
 
interface Props {
  data: CatalogSubjectRow[]
}
 
export function CatalogTable({ data }: Props) {
  const columns = useMemo(() => catalogColumns, [])
 
  const { table } = useDataTable<CatalogSubjectRow>({
    data,
    columns,
    pageCount: 1,
    initialState: {
      pagination: { pageIndex: 0, pageSize: data.length || 50 },
    },
  })
 
  return <DataTable table={table} />
}

Callback pattern (avoid hooks in cells)

// columns.tsx
export interface TeacherColumnCallbacks {
  onView?: (row: TeacherRow) => void
  onEdit?: (row: TeacherRow) => void
  onDelete?: (row: TeacherRow) => void
}
 
export const getTeacherColumns = (
  dictionary?: Dictionary["school"]["teachers"],
  lang?: Locale,
  callbacks?: TeacherColumnCallbacks
): ColumnDef<TeacherRow>[] => [
  {
    id: "actions",
    cell: ({ row }) => (
      <Button onClick={() => callbacks?.onEdit?.(row.original)}>Edit</Button>
    ),
  },
]
 
// table.tsx
const columns = useMemo(
  () => getTeacherColumns(dictionary, lang, callbacks),
  [dictionary, lang, callbacks]
)

Load-more pattern

const handleLoadMore = useCallback(async () => {
  if (isLoading || !hasMore) return
  setIsLoading(true)
  try {
    const result = await getDomains({ page: nextPage, perPage })
    if (result.success && result.data.length > 0) {
      setData((prev) => [...prev, ...result.data])
      setCurrentPage(nextPage)
    }
  } finally {
    setIsLoading(false)
  }
}, [currentPage, perPage, isLoading, hasMore])
 
return (
  <DataTable
    table={table}
    paginationMode="load-more"
    hasMore={hasMore}
    isLoading={isLoading}
    onLoadMore={handleLoadMore}
  >
    <DataTableToolbar table={table} />
  </DataTable>
)

Column meta for toolbar

meta: {
  label: "Status",
  variant: "select",          // "text" = search input, "select" = dropdown
  placeholder: "Search...",
  options: [
    { label: "Active", value: "active" },
    { label: "Inactive", value: "inactive" },
  ],
}

URL state syncs via nuqs and createSearchParamsCache() — see List Params.

Anti-patterns

  • useModal() inside cell renderers — violates Rules of Hooks. Use callbacks.
  • Row type inlined in columns.tsx — define in types.ts instead.
  • Monolithic columns.tsx files (e.g. transaction-history/columns.tsx) — split concerns.
  • receipt/table.tsx shadowing the DataTable import — rename to ReceiptTable.
  • Fetching inside table.tsx — server fetches via content.tsx. Load-more is the only exception.

Naming

ExportPatternExample
Static columns<entity>ColumnsdomainColumns
Factory columnsget<Entity>ColumnsgetTeacherColumns
Callbacks<Entity>ColumnCallbacksTeacherColumnCallbacks
Row type<Entity>RowTeacherRow
Table component<Entity>TableDomainsTable

File layout

src/components/<feature>/
  types.ts          # RowType
  config.ts         # Status variants, filter options
  columns.tsx       # ColumnDef[]
  table.tsx         # DataTable consumer
  actions.ts        # Server actions (load-more)
  content.tsx       # Server component (passes data)

See also

  • Pattern
  • Types
  • List Params
  • Content
FormDetail

On This Page

Categories — columns.tsxCategories — table.tsxRulesCanonical example — minimal tableCallback pattern (avoid hooks in cells)Load-more patternColumn meta for toolbarAnti-patternsNamingFile layoutSee also

Built by Databayt ·

Welcome to balqalam.

A great journey is about to begin.