Glrk UI

Data Table

A simplified wrapper for Shadcn Data Table with flexible option handling and automatic type conversion

EmailStatus
EMP-1000
John Doe
john.doe@company.com
Engineering
Manager
Active
$71,045.00
2023-04-24
New York
EMP-1001
Jane Smith
jane.smith@company.com
Marketing
Senior
Inactive
$117,263.00
2022-03-05
San Francisco
EMP-1002
Mike Johnson
mike.johnson@company.com
Sales
Junior
Pending
$60,040.00
2023-05-23
London
EMP-1003
Sarah Williams
sarah.williams@company.com
HR
Lead
On Leave
$64,254.00
2023-11-21
Tokyo
EMP-1004
David Brown
david.brown@company.com
Finance
Intern
Active
$91,545.00
2024-05-26
Berlin
EMP-1005
Emily Davis
emily.davis@company.com
Engineering
Manager
Inactive
$60,626.00
2023-02-02
New York
EMP-1006
Michael Wilson
michael.wilson@company.com
Marketing
Senior
Pending
$99,104.00
2021-10-04
San Francisco
EMP-1007
Jessica Moore
jessica.moore@company.com
Sales
Junior
On Leave
$54,200.00
2022-12-02
London
EMP-1008
Christopher Taylor
christopher.taylor@company.com
HR
Lead
Active
$123,507.00
2021-05-03
Tokyo
EMP-1009
Amanda Anderson
amanda.anderson@company.com
Finance
Intern
Inactive
$71,782.00
2021-07-16
Berlin
Total: 30 row(s)

Rows per page

Page 1 of 3

Installation

npx shadcn@latest add @glrk-ui/data-table

Data table with virtualization.

npx shadcn@latest add @glrk-ui/data-table @glrk-ui/data-table-virtual

If you haven't set up the prerequisites yet, check out Prerequest section.

npm install @tanstack/react-table

Add following shadcn components: button, table, command, popover, dropdown-menu, select, badge.

Update same components from our site.

ui/data-table/column-faceted-filter.tsx
import { Column } from "@tanstack/react-table";

import { getLabel, getValue, isGroup } from "@/lib/utils";

import { MultiSelectCombobox, type multiSelectComboboxProps } from "../combobox";

interface ColumnFacetedFilterProps<TData, TValue>
  extends Omit<multiSelectComboboxProps, 'options' | 'value' | 'onValueChange' | 'label'> {
  column?: Column<TData, TValue>
  title: React.ReactNode
  options: optionsT
}

function change(option: allowedPrimitiveT | optionT, facets?: Map<any, number>) {
  const value = getValue(option)
  const label = getLabel(option)

  return {
    label: <>
      {label}
      {facets?.get(value) && (
        <span className="ml-auto flex h-4 w-4 items-center justify-center text-xs">
          {facets.get(value)}
        </span>
      )}</>,
    value,
  }
}

export function ColumnFacetedFilter<TData, TValue>({
  column,
  title,
  options,
  ...props
}: ColumnFacetedFilterProps<TData, TValue>) {
  const facets = column?.getFacetedUniqueValues()

  const newOptions = options.map(option => {
    if (isGroup(option)) {
      return {
        ...option,
        options: option.options.map(o => change(o, facets))
      }
    }

    return change(option, facets)
  })

  function onSelect(selected: allowedPrimitiveT[]) {
    column?.setFilterValue(selected?.length ? selected : undefined)
  }

  return (
    <MultiSelectCombobox
      options={newOptions}
      value={column?.getFilterValue() as string[]}
      onValueChange={onSelect}
      label={typeof title === "object" ? title : <span className="font-semibold">{title}</span>}
      indicatorAt="left"
      contentCls="w-fit"
      matchTriggerWidth={false}
      {...props}
    />
  )
}
ui/data-table/column-filter.tsx
import { Column } from "@tanstack/react-table";

import { MultiSelectCombobox, type multiSelectComboboxProps } from "../combobox";

interface ColumndFilterProps<TData, TValue>
  extends Omit<multiSelectComboboxProps, 'options' | 'value' | 'onValueChange' | 'label'> {
  column?: Column<TData, TValue>
  title: React.ReactNode
  options: optionsT
}

export function ColumnFilter<TData, TValue>({
  column,
  title,
  options,
  ...props
}: ColumndFilterProps<TData, TValue>) {
  function onSelect(selected: allowedPrimitiveT[]) {
    column?.setFilterValue(selected?.length ? selected : undefined)
  }

  return (
    <MultiSelectCombobox
      options={options}
      value={column?.getFilterValue() as string[]}
      onValueChange={onSelect}
      label={typeof title === "object" ? title : <span className="font-semibold">{title}</span>}
      contentCls="w-fit"
      matchTriggerWidth={false}
      {...props}
    />
  )
}
ui/data-table/column-header.tsx
import { ArrowDown, ArrowUp, ChevronsUpDown, EyeOff } from "lucide-react";
import { Column } from "@tanstack/react-table";

import { cn } from "@/lib/utils";

import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";

interface ColumnHeaderProps<TData, TValue> {
  className?: string
  column: Column<TData, TValue>
  title: React.ReactNode
}

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

  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button
          variant="ghost"
          className={cn("-ml-2", className)}
        >
          {title}
          {column.getIsSorted() === "desc" ? (
            <ArrowDown />
          ) : column.getIsSorted() === "asc" ? (
            <ArrowUp />
          ) : (
            <ChevronsUpDown />
          )}
        </Button>
      </DropdownMenuTrigger>

      <DropdownMenuContent align="start">
        <DropdownMenuItem
          onClick={() => column.getIsSorted() !== "asc" ? column.toggleSorting(false) : column.clearSorting()}
        >
          <ArrowUp className="h-3.5 w-3.5 text-muted-foreground/70" />
          Asc
        </DropdownMenuItem>

        <DropdownMenuItem
          onClick={() => column.getIsSorted() !== "desc" ? column.toggleSorting(true) : column.clearSorting()}
        >
          <ArrowDown className="h-3.5 w-3.5 text-muted-foreground/70" />
          Desc
        </DropdownMenuItem>

        <DropdownMenuSeparator />

        <DropdownMenuItem onClick={() => column.toggleVisibility(false)}>
          <EyeOff className="h-3.5 w-3.5 text-muted-foreground/70" />
          Hide Column
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  )
}
ui/data-table/column-sorter.tsx
import { ChevronsDown, ChevronsUp, ChevronsUpDown } from "lucide-react";
import { Column } from "@tanstack/react-table";

import { cn } from "@/lib/utils";

import { Button } from "@/components/ui/button";

interface ColumnHeaderProps<TData, TValue> {
  className?: string
  column: Column<TData, TValue>
  title: React.ReactNode
}

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

  const sorted = column.getIsSorted()

  function onSort() {
    if (sorted === "asc") {
      column.toggleSorting(true)
    } else if (sorted === "desc") {
      column.clearSorting()
    } else {
      column.toggleSorting(false)
    }
  }

  return (
    <Button
      variant="ghost"
      className={cn("-ml-2", className)}
      onClick={onSort}
    >
      {title}
      {sorted === "desc" ? (
        <ChevronsDown className="ml-4 opacity-80" />
      ) : sorted === "asc" ? (
        <ChevronsUp className="ml-4 opacity-80" />
      ) : (
        <ChevronsUpDown className="ml-4 opacity-80" />
      )}
    </Button>
  )
}
ui/data-table/column-toggle.tsx
"use client";

import { DropdownMenuTrigger } from "@radix-ui/react-dropdown-menu";
import { Settings2 } from "lucide-react";
import { Table } from "@tanstack/react-table";

import { Button } from "@/components/ui/button";
import {
  DropdownMenu,
  DropdownMenuCheckboxItem,
  DropdownMenuContent,
  DropdownMenuLabel,
  DropdownMenuSeparator,
} from "@/components/ui/dropdown-menu";

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

export function ColumnToggle<TData>({ table }: ColumnToggleProps<TData>) {
  return (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="outline">
          <Settings2 />
          View
        </Button>
      </DropdownMenuTrigger>

      <DropdownMenuContent align="end" className="w-[150px]">
        <DropdownMenuLabel>Toggle columns</DropdownMenuLabel>
        <DropdownMenuSeparator />
        {table
          .getAllColumns()
          .filter(
            (column) =>
              typeof column.accessorFn !== "undefined" && column.getCanHide()
          )
          .map((column) => (
            <DropdownMenuCheckboxItem
              key={column.id}
              className="capitalize"
              checked={column.getIsVisible()}
              onCheckedChange={(value) => column.toggleVisibility(!!value)}
            >
              {column.id?.replace("_", " ")}
            </DropdownMenuCheckboxItem>
          ))}
      </DropdownMenuContent>
    </DropdownMenu>
  )
}
ui/data-table/data-table.tsx
"use client";

import { flexRender, Table as TanstackTable } from "@tanstack/react-table";

import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

interface DataTableProps<TData> {
  table: TanstackTable<TData>
  emptyMessage?: string
  className?: string
}

export function DataTable<TData>({
  table,
  emptyMessage = "No matching results.",
  className = "",
}: DataTableProps<TData>) {
  const columnCount = table?.getAllColumns()?.length
  const rows = table?.getRowModel()?.rows
  const hasRows = rows?.length > 0

  return (
    <Table className={className}>
      <TableHeader>
        {table?.getHeaderGroups().map((headerGroup) => (
          <TableRow key={headerGroup.id} className="hover:bg-transparent">
            {headerGroup.headers.map((header) => (
              <TableHead key={header.id} className="text-theme-grey-text">
                {header.isPlaceholder ? null : flexRender(
                  header.column.columnDef.header,
                  header.getContext()
                )}
              </TableHead>
            ))}
          </TableRow>
        ))}
      </TableHeader>

      <TableBody>
        {hasRows ? (
          rows.map((row) => (
            <TableRow
              key={row.id}
              data-state={row.getIsSelected() && "selected"}
            >
              {row.getVisibleCells().map((cell) => (
                <TableCell key={cell.id} className="text-[13px] capitalize">
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </TableCell>
              ))}
            </TableRow>
          ))
        ) : (
          <TableRow className="hover:bg-transparent">
            <TableCell colSpan={columnCount} className="border-b">
              <div className="dc h-32 my-4 text-sm text-center">
                {emptyMessage}
              </div>
            </TableCell>
          </TableRow>
        )}
      </TableBody>
    </Table>
  )
}
ui/data-table/filter-group.tsx
import { useState } from "react";
import { CirclePlus } from "lucide-react";
import { Table } from "@tanstack/react-table";

import { DropdownCheckboxWrapper } from "../dropdown-menu-wrapper";
import { ColumnFilter } from "./column-filter";
import { Button } from "../button";

interface FilterGroupProps<TData> {
  table: Table<TData>
  options: {
    value: string
    lable: React.ReactNode
    options: optionsT
  }[]
  indicatorAt?: indicatorAtT
}

export function FilterGroup<TData>({ table, options, indicatorAt }: FilterGroupProps<TData>) {
  const [selected, setSelected] = useState<allowedPrimitiveT[]>([])

  return (
    <>
      {
        options
          .filter(f => selected.includes(f.value))
          .map(opt => (
            <ColumnFilter
              key={opt.value}
              title={opt.lable}
              column={table.getColumn(opt.value)}
              options={opt.options}
            />
          ))
      }

      <DropdownCheckboxWrapper
        checked={selected}
        onCheckedChange={(val, checked) => setSelected(prev => !checked ? prev.filter(p => !p) : [...prev, val])}
        options={options.map(m => ({ label: m.lable, value: m.value }))}
        indicatorAt={indicatorAt}
      >
        <Button variant="outline">
          <CirclePlus className="size-4" />
          <span>Filter</span>
        </Button>
      </DropdownCheckboxWrapper>
    </>
  )
}
ui/data-table/pagination.tsx
import { ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight } from "lucide-react";
import { Table } from "@tanstack/react-table";

import { SelectWrapper } from "@/components/ui/select";
import { Button } from "@/components/ui/button";

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

export function Pagination<TData>({ table }: PaginationProps<TData>) {
  return (
    <div className="flex items-center justify-between flex-wrap gap-2 px-2 mt-4">
      <div className="flex-1 whitespace-nowrap text-sm text-muted-foreground">
        Total: {table.getFilteredRowModel().rows.length} row(s)
      </div>

      <div className="flex items-center gap-2">
        <p className="text-xs">Rows per page</p>
        <SelectWrapper
          value={`${table.getState().pagination.pageSize}`}
          onValueChange={(value) => table.setPageSize(Number(value))}
          options={[10, 20, 30, 40, 50]}
          placeholder={`${table.getState().pagination.pageSize}`}
          triggerCls="h-8 w-[70px]"
        />
      </div>

      <div className="text-xs mx-2">
        Page {table.getState().pagination.pageIndex + 1} of{" "}
        {table.getPageCount()}
      </div>

      <div className="flex items-center gap-2">
        <Button
          variant="outline"
          className="hidden h-8 w-8 p-0 lg:flex"
          onClick={() => table.setPageIndex(0)}
          disabled={!table.getCanPreviousPage()}
        >
          <span className="sr-only">Go to first page</span>
          <ChevronsLeft className="size-4" />
        </Button>

        <Button
          variant="outline"
          className="h-8 w-8 p-0"
          onClick={() => table.previousPage()}
          disabled={!table.getCanPreviousPage()}
        >
          <span className="sr-only">Go to previous page</span>
          <ChevronLeft className="size-4" />
        </Button>

        <Button
          variant="outline"
          className="h-8 w-8 p-0"
          onClick={() => table.nextPage()}
          disabled={!table.getCanNextPage()}
        >
          <span className="sr-only">Go to next page</span>
          <ChevronRight className="size-4" />
        </Button>

        <Button
          variant="outline"
          className="hidden h-8 w-8 p-0 lg:flex"
          onClick={() => table.setPageIndex(table.getPageCount() - 1)}
          disabled={!table.getCanNextPage()}
        >
          <span className="sr-only">Go to last page</span>
          <ChevronsRight className="size-4" />
        </Button>
      </div>
    </div>
  )
}
ui/data-table/use-table.ts
"use client";

import { useState } from "react";

import {
  ColumnDef,
  ColumnFiltersState,
  SortingState,
  VisibilityState,
  getCoreRowModel,
  getFacetedRowModel,
  getFacetedUniqueValues,
  getFilteredRowModel,
  getPaginationRowModel,
  getSortedRowModel,
  useReactTable,
} from "@tanstack/react-table";

interface useTableProps<TData, TValue> {
  data: TData[];
  columns: ColumnDef<TData, TValue>[];
}

export function useTable<TData, TValue>({ data, columns }: useTableProps<TData, TValue>) {
  const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({})
  const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([])
  const [sorting, setSorting] = useState<SortingState>([])

  const [rowSelection, setRowSelection] = useState({})
  const [globalFilter, setGlobalFilter] = useState('')

  return useReactTable({
    data,
    columns,
    state: {
      sorting,
      columnVisibility,
      rowSelection,
      columnFilters,
      globalFilter,
    },
    enableRowSelection: true,
    onRowSelectionChange: setRowSelection,
    onSortingChange: setSorting,
    onColumnFiltersChange: setColumnFilters,
    onColumnVisibilityChange: setColumnVisibility,
    onGlobalFilterChange: setGlobalFilter,
    getCoreRowModel: getCoreRowModel(),
    getFilteredRowModel: getFilteredRowModel(),
    getPaginationRowModel: getPaginationRowModel(),
    getSortedRowModel: getSortedRowModel(),
    getFacetedRowModel: getFacetedRowModel(),
    getFacetedUniqueValues: getFacetedUniqueValues(),
  })
}

export default useTable
ui/data-table/index.tsx
export * from "./column-faceted-filter";
export * from "./column-header";
export * from "./column-filter";
export * from "./column-sorter";
export * from "./column-toggle";
export * from "./filter-group";
export * from "./pagination";
export * from "./data-table";
export * from "./use-table";

If you wish to add DataTableVirtualized

npm install @tanstack/react-virtual
ui/data-table/data-table-virtualized.tsx
"use client";

import { useEffect, useRef } from "react";
import { type VirtualizerOptions, useVirtualizer } from "@tanstack/react-virtual";
import { flexRender, Table as TanstackTable } from "@tanstack/react-table";
import { Loader } from "lucide-react";

import { cn } from "@/lib/utils";

import {
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

interface DataTableProps<TData> {
  table: TanstackTable<TData>
  emptyMessage?: string
  className?: string
  hasNextPage?: boolean
  isFetchingNextPage?: boolean
  fetchNextPage?: () => void
  virtualizerOptions?: Partial<Omit<VirtualizerOptions<HTMLDivElement, Element>, 'count' | 'getScrollElement'>>
}

export function DataTableVirtualized<TData>({
  table,
  emptyMessage = "No matching results.",
  className = "",
  hasNextPage = false,
  isFetchingNextPage = false,
  fetchNextPage = () => { },
  virtualizerOptions,
}: DataTableProps<TData>) {
  const rows = table.getRowModel().rows
  const columnCount = table.getAllColumns().length
  const hasRows = rows.length > 0

  const parentRef = useRef<HTMLDivElement>(null)

  const virtualizer = useVirtualizer({
    count: hasNextPage ? rows.length + 1 : rows.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 81,
    overscan: 10,
    ...(virtualizerOptions ?? {}),
  })

  const virtualItems = virtualizer.getVirtualItems()

  useEffect(() => {
    const [lastItem] = [...virtualItems].reverse()

    if (!lastItem) return

    if (lastItem.index >= rows.length - 1 && hasNextPage && !isFetchingNextPage) {
      fetchNextPage?.()
    }
  }, [rows.length, hasNextPage, virtualItems, isFetchingNextPage, fetchNextPage])

  return (
    <div
      ref={parentRef}
      className={cn("overflow-auto", className)}
    >
      <div style={{ height: `${virtualizer.getTotalSize()}px` }}>
        <table className="w-full caption-bottom text-sm">
          <TableHeader>
            {table.getHeaderGroups().map((headerGroup) => (
              <TableRow key={headerGroup.id} className="hover:bg-transparent">
                {headerGroup.headers.map((header) => (
                  <TableHead key={header.id} className="text-theme-grey-text">
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                        header.column.columnDef.header,
                        header.getContext()
                      )}
                  </TableHead>
                ))}
              </TableRow>
            ))}
          </TableHeader>

          <TableBody>
            {hasRows ? (
              virtualItems.map((virtualRow, index) => {
                const isLoaderRow = virtualRow.index > rows.length - 1
                const row = rows[virtualRow.index]

                if (!row) {
                  if (isLoaderRow && hasNextPage) {
                    return (
                      <TableRow
                        key="loader"
                        ref={virtualizer.measureElement}
                        data-index={virtualRow.index}
                        style={{
                          height: `${virtualRow.size}px`,
                          transform: `translateY(${virtualRow.start - index * virtualRow.size}px)`,
                        }}
                      >
                        <TableCell colSpan={columnCount}>
                          <div className="dc">
                            <Loader className="animate-spin" />
                          </div>
                        </TableCell>
                      </TableRow>
                    )
                  }
                  return null
                }

                return (
                  <TableRow
                    key={row.id}
                    ref={virtualizer.measureElement}
                    data-state={row?.getIsSelected?.() && "selected"}
                    data-index={virtualRow.index}
                    className="hover:bg-muted/40"
                    style={{
                      height: `${virtualRow.size}px`,
                      transform: `translateY(${virtualRow.start - (isLoaderRow ? index - 1 : index) * virtualRow.size}px)`,
                    }}
                  >
                    {
                      row?.getVisibleCells()?.map((cell) => (
                        <TableCell
                          key={cell.id}
                          className="text-[13px] capitalize"
                        >
                          {flexRender(
                            cell.column.columnDef.cell,
                            cell.getContext()
                          )}
                        </TableCell>
                      ))
                    }
                  </TableRow>
                )
              })
            ) : (
              <TableRow className="hover:bg-transparent">
                <TableCell colSpan={columnCount} className="border-b">
                  <div className="dc h-32 my-4 text-sm text-center">{emptyMessage}</div>
                </TableCell>
              </TableRow>
            )}
          </TableBody>
        </table>
      </div>
    </div>
  )
}

add import statement in the ui/data-table/index.tsx

export * from "./data-table-virtualized";
export * from "./column-faceted-filter";
export * from "./column-header";
export * from "./column-filter";
export * from "./column-sorter";
export * from "./column-toggle";
export * from "./filter-group";
export * from "./pagination";
export * from "./data-table";
export * from "./use-table";

Usage

DataTable

import {
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";

import { DataTable } from '@/components/ui/data-table';

function MyTable() {
  const table = useReactTable({ 
    data, 
    columns,
    getCoreRowModel: getCoreRowModel(),
  })
  
  return <DataTable table={table} />
}

DataTableVirtualized

import {
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";

import { DataTableVirtualized } from '@/components/ui/data-table-virtualized';

function MyTable() {
  const {
    data,
    fetchNextPage,
    hasNextPage,
    isFetchingNextPage,
  } = useInfiniteQuery()
  
  const table = useReactTable({ 
    data: data.pages.flat(), 
    columns,
    getCoreRowModel: getCoreRowModel(),
  })
  
  return (
    <DataTableVirtualized
      table={table}
      hasNextPage={hasNextPage}
      isFetchingNextPage={isFetchingNextPage}
      fetchNextPage={fetchNextPage}
      className="h-[600px]" // Fixed height required
    />
  )
}

useTable Hook

Custom hook for managing table state and configuration. Pre-configured with columnVisibility, columnFilters (Faceted), sorting, rowSelection, globalFilter, pagination. So you can use most of the functionality of tanstack-table just using this hook.

import { useTable } from '@/components/ui/use-table';
import { DataTable } from '@/components/ui/data-table';

function MyTable() {
  const table = useTable({ data, columns })
  
  return (
    <>
      //... Other components

      <DataTable table={table} />
    </>
  )
}

ColumnSorter

Simple column header with sorting functionality.

const columns: ColumnDef<User>[] = [
  {
    accessorKey: 'name',
    header: ({ column }) => (
      <ColumnSorter column={column} title="Name" />
    ),
  },
]

ColumnHeader

Advanced column header with dropdown menu for sorting and visibility.

const columns: ColumnDef<User>[] = [
  {
    accessorKey: 'name',
    header: ({ column }) => (
      <ColumnHeader column={column} title="Name" />
    ),
  },
]

ColumnFilter

Multi-select dropdown filter for column values.

<ColumnFilter
  title="Role"
  column={table.getColumn('role')}
  options={['Manager', 'Senior', 'Junior', 'Lead', 'Intern']}
/>

ColumnFacetedFilter

Multi-select dropdown filter with faceted value counts.

<ColumnFacetedFilter
  title="Role"
  column={table.getColumn('role')}
  options={['Manager', 'Senior', 'Junior', 'Lead', 'Intern']}
/>

FilterGroup

Dynamic filter management component that allows adding/removing filters (ColumnFilter).

<FilterGroup
  table={table}
  options={[
    {
      key: 'department',
      lable: 'Department',
      options: ['Engineering', 'Marketing', 'Sales']
    },
    {
      key: 'location',
      lable: 'Location',
      options: ['New York', 'London', 'Tokyo']
    }
  ]}
/>

ColumnToggle

Dropdown menu for showing/hiding table columns.

<ColumnToggle table={table} />

Pagination

Comprehensive pagination controls with page size selection.

<Pagination table={table} />

Note: options array is of optionsT type, so you can pass allowed data. DataTable fully customizable with column array itself.

Reference

ColumndFilter and ColumnFacetedFilter

Prop

Type

ColumnHeader

Prop

Type

ColumnSorter

Prop

Type

ColumnToggle and Pagination

Prop

Type

useTable

Prop

Type

DataTable

Prop

Type

DataTableVirtualized

Prop

Type