सामग्री पर जाएँ

डेटा तालिका

प्रशासक पैनलों, डैशबोर्ड्स और ऑर्डर सूचियों के लिए क्रमबद्ध, फ़िल्टर करने योग्य, पृष्ठबद्ध तालिकाएँ — नियोब्रूटलिस्ट शैली के बॉर्डर और शैडोज़ ट्रीटमेंट के साथ।

डेटा टेबल एक गाइड है, पैकेज्ड कंपोनेंट नहीं: आप <Table /> कंपोनेंट और TanStack Table से अपनी टेबल बनाते हैं — sorting, filtering, pagination और row selection का headless इंजन — नियोब्रूटलिस्ट रेसिपी (मोटे बॉर्डर, कठोर छायाएँ, बोल्ड टाइप) लुक संभालती है।

इसे इन स्थितियों में चुनें:

  • एडमिन पैनल — ऑर्डर, उपयोगकर्ता, इनवॉइस: sortable कॉलम, फ़िल्टर और प्रति-पंक्ति एक्शन मेनू।
  • डैशबोर्ड — पेमेंट या एक्टिविटी टेबल: फ़ॉर्मैटेड सेल, स्टेटस कॉलम, paginated API डेटा।
  • बल्क वर्कफ़्लो — निर्यात, आर्काइव या कई रिकॉर्ड डिलीट के लिए चेकबॉक्स पंक्ति चयन।

परिचय

मैंने जो भी डेटा टेबल या डेटाग्रिड बनाया है, वह अनूठा रहा है. वे सभी अलग-अलग व्यवहार करते हैं, उनकी सॉर्टिंग और फ़िल्टरिंग की विशिष्ट आवश्यकताएँ होती हैं, और वे अलग-अलग डेटा सोर्स के साथ काम करते हैं.

इन सभी विविधताओं को एक ही कंपोनेंट में जोड़ना उचित नहीं है. अगर हम ऐसा करते हैं, तो हम वह लचीलापन खो देंगे जो headless UI प्रदान करता है.

इसलिए, एक data-table कंपोनेंट के बजाय, मुझे लगा कि अपना खुद का बनाने के तरीके पर एक गाइड देना ज़्यादा मददगार होगा.

हम बुनियादी <Table /> कंपोनेंट से शुरू करेंगे और शुरुआत से एक जटिल डेटा टेबल बनाएंगे.

विषय-सूची

यह गाइड आपको दिखाएगी कि अपना खुद का कस्टम डेटा टेबल बनाने के लिए TanStack Table और <Table /> कंपोनेंट का उपयोग कैसे करें. हम निम्नलिखित विषयों को कवर करेंगे:

इंस्टॉलेशन

  1. अपने प्रोजेक्ट में <Table /> कंपोनेंट जोड़ें:
pnpm dlx shadcn@latest add table
npx shadcn@latest add table
yarn dlx shadcn@latest add table
bunx --bun shadcn@latest add table
  1. tanstack/react-table डिपेंडेंसी जोड़ें:
pnpm add @tanstack/react-table
npm install @tanstack/react-table
yarn add @tanstack/react-table
bun add @tanstack/react-table

पूर्वापेक्षाएँ

हम हाल के भुगतान दिखाने के लिए एक टेबल बनाने जा रहे हैं. हमारा डेटा इस तरह दिखता है:

type Payment = {
  id: string
  amount: number
  status: "pending" | "processing" | "success" | "failed"
  email: string
}
 
export const payments: Payment[] = [
  {
    id: "728ed52f",
    amount: 100,
    status: "pending",
    email: "[email protected]",
  },
  {
    id: "489e1d42",
    amount: 125,
    status: "processing",
    email: "[email protected]",
  },
  // ...
]

प्रोजेक्ट स्ट्रक्चर

निम्नलिखित फ़ाइल स्ट्रक्चर बनाकर शुरू करें:

app
└── payments
    ├── columns.tsx
    ├── data-table.tsx
    └── page.tsx

मैं यहाँ Next.js का उदाहरण उपयोग कर रहा हूँ, लेकिन यह किसी भी अन्य React फ्रेमवर्क के साथ काम करता है.

  • columns.tsx (क्लाइंट कंपोनेंट) में हमारी कॉलम परिभाषाएँ होंगी.
  • data-table.tsx (क्लाइंट कंपोनेंट) में हमारा <DataTable /> कंपोनेंट होगा.
  • page.tsx (सर्वर कंपोनेंट) वह जगह है जहाँ हम डेटा फ़ेच करेंगे और अपनी टेबल रेंडर करेंगे.

बुनियादी तालिका

आइए एक बुनियादी तालिका बनाकर शुरू करें.

कॉलम परिभाषाएँ

सबसे पहले, हम अपने कॉलम परिभाषित करेंगे.

app/payments/columns.tsx
"use client"
 
import { ColumnDef } from "@tanstack/react-table"
 
// This type is used to define the shape of our data.
// You can use a Zod schema here if you want.
export type Payment = {
  id: string
  amount: number
  status: "pending" | "processing" | "success" | "failed"
  email: string
}
 
export const columns: ColumnDef<Payment>[] = [
  {
    accessorKey: "status",
    header: "Status",
  },
  {
    accessorKey: "email",
    header: "Email",
  },
  {
    accessorKey: "amount",
    header: "Amount",
  },
]

<DataTable /> कंपोनेंट

इसके बाद, हम अपनी टेबल रेंडर करने के लिए एक <DataTable /> कंपोनेंट बनाएंगे.

app/payments/data-table.tsx
"use client"
 
import {
  ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table"
 
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table"
 
interface DataTableProps<TData, TValue> {
  columns: ColumnDef<TData, TValue>[]
  data: TData[]
}
 
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  })
 
  return (
    <div className="overflow-hidden rounded-md border">
      <Table>
        <TableHeader>
          {table.getHeaderGroups().map((headerGroup) => (
            <TableRow key={headerGroup.id}>
              {headerGroup.headers.map((header) => {
                return (
                  <TableHead key={header.id}>
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext()
                        )}
                  </TableHead>
                )
              })}
            </TableRow>
          ))}
        </TableHeader>
        <TableBody>
          {table.getRowModel().rows?.length ? (
            table.getRowModel().rows.map((row) => (
              <TableRow
                key={row.id}
                data-state={row.getIsSelected() && "selected"}
              >
                {row.getVisibleCells().map((cell) => (
                  <TableCell key={cell.id}>
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </TableCell>
                ))}
              </TableRow>
            ))
          ) : (
            <TableRow>
              <TableCell colSpan={columns.length} className="h-24 text-center">
                No results.
              </TableCell>
            </TableRow>
          )}
        </TableBody>
      </Table>
    </div>
  )
}

तालिका रेंडर करें

अंत में, हम अपने पेज कंपोनेंट में अपनी टेबल रेंडर करेंगे.

app/payments/page.tsx
import { columns, Payment } from "./columns"
import { DataTable } from "./data-table"
 
async function getData(): Promise<Payment[]> {
  // Fetch data from your API here.
  return [
    {
      id: "728ed52f",
      amount: 100,
      status: "pending",
      email: "[email protected]",
    },
    // ...
  ]
}
 
export default async function DemoPage() {
  const data = await getData()
 
  return (
    <div className="container mx-auto py-10">
      <DataTable columns={columns} data={data} />
    </div>
  )
}

सेल फ़ॉर्मैटिंग

आइए डॉलर राशि दिखाने के लिए amount सेल को फ़ॉर्मैट करें. हम सेल को दाईं ओर भी अलाइन करेंगे.

कॉलम परिभाषा अपडेट करें

amount के लिए header और cell परिभाषाओं को इस प्रकार अपडेट करें:

app/payments/columns.tsx
export const columns: ColumnDef<Payment>[] = [
  {
    accessorKey: "amount",
    header: () => <div className="text-right">Amount</div>,
    cell: ({ row }) => {
      const amount = parseFloat(row.getValue("amount"))
      const formatted = new Intl.NumberFormat("en-US", {
        style: "currency",
        currency: "USD",
      }).format(amount)
 
      return <div className="text-right font-medium">{formatted}</div>
    },
  },
]

आप अन्य सेल और हेडर को फ़ॉर्मैट करने के लिए इसी तरीके का उपयोग कर सकते हैं.

पंक्ति क्रियाएँ

आइए अपनी टेबल में पंक्ति क्रियाएँ जोड़ें. इसके लिए हम <DropdownMenu /> कंपोनेंट का उपयोग करेंगे.

कॉलम परिभाषा अपडेट करें

एक नया actions कॉलम जोड़ने के लिए हमारी कॉलम परिभाषा अपडेट करें. actions सेल एक <DropdownMenu /> कंपोनेंट रिटर्न करता है.

app/payments/columns.tsx
"use client"
 
import { ColumnDef } from "@tanstack/react-table"
import { MoreHorizontal } from "lucide-react"
 
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
 
export const columns: ColumnDef<Payment>[] = [
  // ...
  {
    id: "actions",
    cell: ({ row }) => {
      const payment = row.original
 
      return (
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="ghost" className="h-8 w-8 p-0">
              <span className="sr-only">Open menu</span>
              <MoreHorizontal className="h-4 w-4" />
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            <DropdownMenuLabel>Actions</DropdownMenuLabel>
            <DropdownMenuItem
              onClick={() => navigator.clipboard.writeText(payment.id)}
            >
              Copy payment ID
            </DropdownMenuItem>
            <DropdownMenuSeparator />
            <DropdownMenuItem>View customer</DropdownMenuItem>
            <DropdownMenuItem>View payment details</DropdownMenuItem>
          </DropdownMenuContent>
        </DropdownMenu>
      )
    },
  },
  // ...
]

आप cell फ़ंक्शन में row.original का उपयोग करके पंक्ति डेटा एक्सेस कर सकते हैं. अपनी पंक्ति की क्रियाओं को हैंडल करने के लिए इसका उपयोग करें, उदाहरण के लिए, अपने API को DELETE कॉल करने के लिए id का उपयोग करें.

पेजिनेशन

इसके बाद, हम अपनी टेबल में पेजिनेशन जोड़ेंगे.

<DataTable> अपडेट करें

app/payments/data-table.tsx
import {
  ColumnDef,
  flexRender,
  getCoreRowModel,
  getPaginationRowModel,
  useReactTable,
} from "@tanstack/react-table"
 
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  })
 
  // ...
}

यह आपकी पंक्तियों को स्वचालित रूप से 10 के पेज में पेजिनेट कर देगा. पेज साइज़ को कस्टमाइज़ करने और मैनुअल पेजिनेशन लागू करने के बारे में अधिक जानकारी के लिए पेजिनेशन डॉक्स देखें.

पेजिनेशन कंट्रोल जोड़ें

हम <Button /> कंपोनेंट और table.previousPage(), table.nextPage() API मेथड का उपयोग करके अपनी टेबल में पेजिनेशन कंट्रोल जोड़ सकते हैं.

app/payments/data-table.tsx
import { Button } from "@/components/ui/button"
 
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
  })
 
  return (
    <div>
      <div className="overflow-hidden rounded-md border">
        <Table>
          { // .... }
        </Table>
      </div>
      <div className="flex items-center justify-end space-x-2 py-4">
        <Button
          variant="outline"
          size="sm"
          onClick={() => table.previousPage()}
          disabled={!table.getCanPreviousPage()}
        >
          Previous
        </Button>
        <Button
          variant="outline"
          size="sm"
          onClick={() => table.nextPage()}
          disabled={!table.getCanNextPage()}
        >
          Next
        </Button>
      </div>
    </div>
  )
}

अधिक उन्नत पेजिनेशन कंपोनेंट के लिए रीयूज़ेबल कंपोनेंट सेक्शन देखें.

सॉर्टिंग

आइए email कॉलम को सॉर्ट करने योग्य बनाएं.

<DataTable> अपडेट करें

app/payments/data-table.tsx
"use client"
 
import * as React from "react"
import {
  ColumnDef,
  SortingState,
  flexRender,
  getCoreRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table"
 
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
 
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    onSortingChange: setSorting,
    getSortedRowModel: getSortedRowModel(),
    state: {
      sorting,
    },
  })
 
  return (
    <div>
      <div className="overflow-hidden rounded-md border">
        <Table>{ ... }</Table>
      </div>
    </div>
  )
}

हेडर सेल को सॉर्ट करने योग्य बनाएं

अब हम सॉर्टिंग कंट्रोल जोड़ने के लिए email हेडर सेल को अपडेट कर सकते हैं.

app/payments/columns.tsx
"use client"
 
import { ColumnDef } from "@tanstack/react-table"
import { ArrowUpDown } from "lucide-react"
 
export const columns: ColumnDef<Payment>[] = [
  {
    accessorKey: "email",
    header: ({ column }) => {
      return (
        <Button
          variant="ghost"
          onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
        >
          Email
          <ArrowUpDown className="ml-2 h-4 w-4" />
        </Button>
      )
    },
  },
]

जब उपयोगकर्ता हेडर सेल पर टॉगल करेगा, तो यह टेबल को स्वचालित रूप से सॉर्ट (asc और desc) कर देगा.

फ़िल्टरिंग

आइए अपनी टेबल में ईमेल फ़िल्टर करने के लिए एक सर्च इनपुट जोड़ें.

<DataTable> अपडेट करें

app/payments/data-table.tsx
"use client"
 
import * as React from "react"
import {
  ColumnDef,
  ColumnFiltersState,
  SortingState,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table"
 
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
 
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
    []
  )
 
  const table = useReactTable({
    data,
    columns,
    onSortingChange: setSorting,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
    onColumnFiltersChange: setColumnFilters,
    getFilteredRowModel: getFilteredRowModel(),
    state: {
      sorting,
      columnFilters,
    },
  })
 
  return (
    <div>
      <div className="flex items-center py-4">
        <Input
          placeholder="Filter emails..."
          value={(table.getColumn("email")?.getFilterValue() as string) ?? ""}
          onChange={(event) =>
            table.getColumn("email")?.setFilterValue(event.target.value)
          }
          className="max-w-sm"
        />
      </div>
      <div className="overflow-hidden rounded-md border">
        <Table>{ ... }</Table>
      </div>
    </div>
  )
}

अब email कॉलम के लिए फ़िल्टरिंग सक्षम है. आप अन्य कॉलम में भी फ़िल्टर जोड़ सकते हैं. फ़िल्टर को कस्टमाइज़ करने के बारे में अधिक जानकारी के लिए फ़िल्टरिंग डॉक्स देखें.

दृश्यता

@tanstack/react-table की visibility API का उपयोग करके कॉलम दृश्यता जोड़ना काफी सरल है.

<DataTable> अपडेट करें

app/payments/data-table.tsx
"use client"
 
import * as React from "react"
import {
  ColumnDef,
  ColumnFiltersState,
  SortingState,
  VisibilityState,
  flexRender,
  getCoreRowModel,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table"
 
import { Button } from "@/components/ui/button"
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu"
 
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
    []
  )
  const [columnVisibility, setColumnVisibility] =
    React.useState<VisibilityState>({})
 
  const table = useReactTable({
    data,
    columns,
    onSortingChange: setSorting,
    onColumnFiltersChange: setColumnFilters,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    onColumnVisibilityChange: setColumnVisibility,
    state: {
      sorting,
      columnFilters,
      columnVisibility,
    },
  })
 
  return (
    <div>
      <div className="flex items-center py-4">
        <Input
          placeholder="Filter emails..."
          value={table.getColumn("email")?.getFilterValue() as string}
          onChange={(event) =>
            table.getColumn("email")?.setFilterValue(event.target.value)
          }
          className="max-w-sm"
        />
        <DropdownMenu>
          <DropdownMenuTrigger asChild>
            <Button variant="outline" className="ml-auto">
              Columns
            </Button>
          </DropdownMenuTrigger>
          <DropdownMenuContent align="end">
            {table
              .getAllColumns()
              .filter(
                (column) => column.getCanHide()
              )
              .map((column) => {
                return (
                  <DropdownMenuCheckboxItem
                    key={column.id}
                    className="capitalize"
                    checked={column.getIsVisible()}
                    onCheckedChange={(value) =>
                      column.toggleVisibility(!!value)
                    }
                  >
                    {column.id}
                  </DropdownMenuCheckboxItem>
                )
              })}
          </DropdownMenuContent>
        </DropdownMenu>
      </div>
      <div className="overflow-hidden rounded-md border">
        <Table>{ ... }</Table>
      </div>
    </div>
  )
}

यह एक ड्रॉपडाउन मेनू जोड़ता है जिसका उपयोग आप कॉलम दृश्यता टॉगल करने के लिए कर सकते हैं.

पंक्ति चयन

इसके बाद, हम अपनी टेबल में पंक्ति चयन जोड़ने जा रहे हैं.

कॉलम परिभाषाएँ अपडेट करें

app/payments/columns.tsx
"use client"
 
import { ColumnDef } from "@tanstack/react-table"
 
import { Badge } from "@/components/ui/badge"
import { Checkbox } from "@/components/ui/checkbox"
 
export const columns: ColumnDef<Payment>[] = [
  {
    id: "select",
    header: ({ table }) => (
      <Checkbox
        checked={
          table.getIsAllPageRowsSelected() ||
          (table.getIsSomePageRowsSelected() && "indeterminate")
        }
        onCheckedChange={(value) => table.toggleAllPageRowsSelected(!!value)}
        aria-label="Select all"
      />
    ),
    cell: ({ row }) => (
      <Checkbox
        checked={row.getIsSelected()}
        onCheckedChange={(value) => row.toggleSelected(!!value)}
        aria-label="Select row"
      />
    ),
    enableSorting: false,
    enableHiding: false,
  },
]

<DataTable> अपडेट करें

app/payments/data-table.tsx
export function DataTable<TData, TValue>({
  columns,
  data,
}: DataTableProps<TData, TValue>) {
  const [sorting, setSorting] = React.useState<SortingState>([])
  const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
    []
  )
  const [columnVisibility, setColumnVisibility] =
    React.useState<VisibilityState>({})
  const [rowSelection, setRowSelection] = React.useState({})
 
  const table = useReactTable({
    data,
    columns,
    onSortingChange: setSorting,
    onColumnFiltersChange: setColumnFilters,
    getCoreRowModel: getCoreRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    onColumnVisibilityChange: setColumnVisibility,
    onRowSelectionChange: setRowSelection,
    state: {
      sorting,
      columnFilters,
      columnVisibility,
      rowSelection,
    },
  })
 
  return (
    <div>
      <div className="overflow-hidden rounded-md border">
        <Table />
      </div>
    </div>
  )
}

यह प्रत्येक पंक्ति में एक चेकबॉक्स और सभी पंक्तियों को चुनने के लिए हेडर में एक चेकबॉक्स जोड़ता है.

चयनित पंक्तियाँ दिखाएं

आप table.getFilteredSelectedRowModel() API का उपयोग करके चयनित पंक्तियों की संख्या दिखा सकते हैं.

<div className="flex-1 text-sm text-muted-foreground">
  {table.getFilteredSelectedRowModel().rows.length} of{" "}
  {table.getFilteredRowModel().rows.length} row(s) selected.
</div>

रीयूज़ेबल कंपोनेंट

यहाँ कुछ कंपोनेंट दिए गए हैं जिनका उपयोग आप अपनी डेटा टेबल बनाने के लिए कर सकते हैं. ये Tasks डेमो से हैं.

कॉलम हेडर

किसी भी कॉलम हेडर को सॉर्ट करने योग्य और छिपाने योग्य बनाएं.

components/data-table-column-header.tsx
import { type Column } from "@tanstack/react-table"
import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from "lucide-react"

import { cn } from "@/lib/utils"
import { Button } from "@/registry/base/ui/button"
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/registry/base/ui/dropdown-menu"

interface DataTableColumnHeaderProps<
  TData,
  TValue,
> extends React.HTMLAttributes<HTMLDivElement> {
  column: Column<TData, TValue>
  title: string
}

export function DataTableColumnHeader<TData, TValue>({
  column,
  title,
  className,
}: DataTableColumnHeaderProps<TData, TValue>) {
  if (!column.getCanSort()) {
    return <div className={cn(className)}>{title}</div>
  }

  return (
    <div className={cn("flex items-center gap-2", className)}>
      <DropdownMenu>
        <DropdownMenuTrigger
          render={
            <Button
              variant="ghost"
              size="sm"
              className="-ml-3 h-8 data-popup-open:bg-accent"
            />
          }
        >
          <span>{title}</span>
          {column.getIsSorted() === "desc" ? (
            <ArrowDown />
          ) : column.getIsSorted() === "asc" ? (
            <ArrowUp />
          ) : (
            <ChevronsUpDown />
          )}
        </DropdownMenuTrigger>
        <DropdownMenuContent align="start">
          <DropdownMenuItem onClick={() => column.toggleSorting(false)}>
            <ArrowUp />
            Asc
          </DropdownMenuItem>
          <DropdownMenuItem onClick={() => column.toggleSorting(true)}>
            <ArrowDown />
            Desc
          </DropdownMenuItem>
          <DropdownMenuSeparator />
          <DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
            <EyeOff />
            Hide
          </DropdownMenuItem>
        </DropdownMenuContent>
      </DropdownMenu>
    </div>
  )
}
export const columns = [
  {
    accessorKey: "email",
    header: ({ column }) => (
      <DataTableColumnHeader column={column} title="Email" />
    ),
  },
]

पेजिनेशन

अपनी टेबल में पेज साइज़ और चयन संख्या सहित पेजिनेशन कंट्रोल जोड़ें.

import { type Table } from "@tanstack/react-table"
import {
  ChevronLeft,
  ChevronRight,
  ChevronsLeft,
  ChevronsRight,
} from "lucide-react"

import { Button } from "@/registry/base/ui/button"
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/registry/base/ui/select"

const pageSizeItems = [10, 20, 25, 30, 40, 50].map((pageSize) => ({
  label: `${pageSize}`,
  value: `${pageSize}`,
}))

interface DataTablePaginationProps<TData> {
  table: Table<TData>
}

export function DataTablePagination<TData>({
  table,
}: DataTablePaginationProps<TData>) {
  return (
    <div className="flex items-center justify-between px-2">
      <div className="flex-1 text-sm text-muted-foreground">
        {table.getFilteredSelectedRowModel().rows.length} of{" "}
        {table.getFilteredRowModel().rows.length} row(s) selected.
      </div>
      <div className="flex items-center space-x-6 lg:space-x-8">
        <div className="flex items-center space-x-2">
          <p className="text-sm font-medium">Rows per page</p>
          <Select
            items={pageSizeItems}
            value={`${table.getState().pagination.pageSize}`}
            onValueChange={(value) => {
              if (value !== null) {
                table.setPageSize(Number(value))
              }
            }}
          >
            <SelectTrigger className="h-8 w-[70px]">
              <SelectValue />
            </SelectTrigger>
            <SelectContent side="top">
              {pageSizeItems.map((item) => (
                <SelectItem key={item.value} value={item.value}>
                  {item.label}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
        </div>
        <div className="flex w-[100px] items-center justify-center text-sm font-medium">
          Page {table.getState().pagination.pageIndex + 1} of{" "}
          {table.getPageCount()}
        </div>
        <div className="flex items-center space-x-2">
          <Button
            variant="outline"
            size="icon"
            className="hidden size-8 lg:flex"
            onClick={() => table.setPageIndex(0)}
            disabled={!table.getCanPreviousPage()}
          >
            <span className="sr-only">Go to first page</span>
            <ChevronsLeft />
          </Button>
          <Button
            variant="outline"
            size="icon"
            className="size-8"
            onClick={() => table.previousPage()}
            disabled={!table.getCanPreviousPage()}
          >
            <span className="sr-only">Go to previous page</span>
            <ChevronLeft />
          </Button>
          <Button
            variant="outline"
            size="icon"
            className="size-8"
            onClick={() => table.nextPage()}
            disabled={!table.getCanNextPage()}
          >
            <span className="sr-only">Go to next page</span>
            <ChevronRight />
          </Button>
          <Button
            variant="outline"
            size="icon"
            className="hidden size-8 lg:flex"
            onClick={() => table.setPageIndex(table.getPageCount() - 1)}
            disabled={!table.getCanNextPage()}
          >
            <span className="sr-only">Go to last page</span>
            <ChevronsRight />
          </Button>
        </div>
      </div>
    </div>
  )
}
<DataTablePagination table={table} />

कॉलम टॉगल

कॉलम दृश्यता टॉगल करने के लिए एक कंपोनेंट.

"use client"

import { type Table } from "@tanstack/react-table"
import { Settings2 } from "lucide-react"

import { Button } from "@/registry/base/ui/button"
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/registry/base/ui/dropdown-menu"

export function DataTableViewOptions<TData>({
  table,
}: {
  table: Table<TData>
}) {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger
        render={
          <Button
            variant="outline"
            size="sm"
            className="ml-auto hidden h-8 lg:flex"
          />
        }
      >
        <Settings2 />
        View
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end" className="w-[150px]">
        {/* GroupLabel (Base UI) needs a Group ancestor or it throws error #31. */}
        <DropdownMenuGroup>
          <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
        </DropdownMenuGroup>
        <DropdownMenuSeparator />
        {table
          .getAllColumns()
          .filter(
            (column) =>
              typeof column.accessorFn !== "undefined" && column.getCanHide()
          )
          .map((column) => {
            return (
              <DropdownMenuCheckboxItem
                key={column.id}
                className="capitalize"
                checked={column.getIsVisible()}
                onCheckedChange={(value) => column.toggleVisibility(!!value)}
              >
                {column.id}
              </DropdownMenuCheckboxItem>
            )
          })}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}
<DataTableViewOptions table={table} />

RTL

Neobrutalism में RTL सपोर्ट सक्षम करने के लिए, RTL कॉन्फ़िगरेशन गाइड देखें.

एक्सेसिबिलिटी

TanStack Table headless है — कोई मार्कअप नहीं रेंडर करता, इसलिए एक्सेसिबिलिटी इस गाइड के एलिमेंटों से आती है। <Table /> कंपोनेंट नेटिव <table>, <th> और <td> आउटपुट करता है, जो स्क्रीन रीडर को WAI-ARIA Table पैटर्न के अनुसार पंक्ति-कॉलम संदर्भ देते हैं। बनाते समय दो बातें रखें: वर्तमान में sorted हेडर पर aria-sort सेट करें, और चयन चेकबॉक्स पर aria-label तथा आइकन-ओनली ट्रिगर पर sr-only टेक्स्ट बनाए रखें (ऊपर के स्निपेट दोनों करते हैं)।

इस गाइड का हर कंट्रोल नेटिव बटन, चेकबॉक्स या इनपुट है, इसलिए कीबोर्ड व्यवहार ब्राउज़र डिफ़ॉल्ट है:

कीबोर्ड इंटरैक्शन:

कुंजीक्रिया
Tab / Shift + Tabटेबल कंट्रोलों के बीच फ़ोकस ले जाएँ — फ़िल्टर इनपुट, सॉर्ट हेडर, पंक्ति मेनू, पेजिनेशन
Space / Enterफ़ोकस किए गए सॉर्ट या पेजिनेशन बटन को सक्रिय करें
Spaceफ़ोकस किए गए पंक्ति या select-all चेकबॉक्स को टॉगल करें