🖍️
Developer Note
  • Welcome
  • Git
    • Eslint & Prettier & Stylelint & Husky
  • Programming Language
    • JavaScript
      • Script Async vs Defer
      • Module
      • Const VS Let VS Var
      • Promise
      • Event Loop
      • Execution Context
      • Hoisting
      • Closure
      • Event Buddling and Capturing
      • Garbage Collection
      • This
      • Routing
      • Debounce and Throttle
      • Web Component
      • Iterator
      • Syntax
      • String
      • Array
      • Object
      • Proxy & Reflect
      • ProtoType
      • Class
      • Immutability
      • Typeof & Instanceof
      • Npm (Node package manager)
    • TypeScript
      • Utility Type
      • Type vs Interface
      • Any vs Unknown vs Never
      • Void and undefined
      • Strict Mode
      • Namespace
      • Enum
      • Module
      • Generic
    • Python
      • Local Development
      • Uv
      • Asyncio & Event loop
      • Context Manager
      • Iterator & Generator
      • Fast API
      • Pydantic & Data Class
    • Java
      • Compilation and Execution
      • Data Type
      • Enumeration
      • Data Structure
      • Try Catch
      • InputStream and OutputStream
      • Concurrent
      • Unicode Block
      • Build Tools
      • Servlet
      • Java 8
  • Coding Pattern
    • MVC vs MVVM
    • OOP vs Functional
    • Error Handling
    • MVC vs Flux
    • Imperative vs Declarative
    • Design Pattern
  • Web Communication
    • REST API
      • Web Hook
      • CORS issue
    • HTTPS
    • GraphQL
      • REST API vs GraphQL
      • Implementation (NodeJS + React)
    • Server-Sent Event
    • Web Socket
    • IP
    • Domain Name System (DNS)
  • Frontend
    • Progressive Web App (PWA)
    • Single Page & Multiple Page Application
    • Search Engine Optimiaztion (SEO)
    • Web bundling & Micro-frontend
      • Webpack
        • Using Webpack to build React Application
        • Using Webpack to build react library
      • Vite
      • Using rollup to build react library
      • Implementing micro frontend
    • Web Security
      • CSRF & Nonce
      • XSS
      • Click hijacking
    • Cypress
    • CSS
      • Core
        • Box Model
        • Inline vs Block
        • Flexbox & Grid
        • Pseudo Class
        • Position
      • Tailwind CSS
        • Shadcn
      • CSS In JS
        • Material UI
    • React
      • Core
        • Component Pattern
        • React Lazy & Suspense
        • React Portal
        • Error Boundary
        • Rendering Methods
        • Environment Variable
        • Conditional CSS
        • Memo
        • Forward Reference
        • High Order Component (HOC) & Custom Hook
        • TypeScript
      • State Management
        • Redux
        • Recoil
        • Zustand
      • Routing
        • React Router Dom
      • Data Fetching
        • Axios & Hook
        • React Query
        • Orval
      • Table
        • React Table
      • Form & Validation
        • React Hook Form
        • Zod
      • NextJS
        • Page Router
        • App Router
      • React Native
    • Angular
    • Svelte
      • Svelte Kit
  • Backend
    • Cache
      • Browser Cache
      • Web Browser Storage
      • Proxy
      • Redis
    • Rate limit
    • Monitoring
      • Logging
      • Distributed Tracing
    • Load Test
    • Encryption
    • Authentication
      • Password Protection
      • Cookie & Session
      • JSON Web Token
      • SSO
        • OAuth 2.0
        • OpenID Connect (OIDC)
        • SAML
    • Payment
      • Pre-built
      • Custom
    • File Handling
      • Upload & Download (Front-end)
      • Stream & Buffer
    • Microservice
      • API Gateway
      • Service Discovery
      • Load Balancer
      • Circuit Breaker
      • Message Broker
      • BulkHead & Zipkin
    • Elastic Search
    • Database
      • SQL
        • Group By vs Distinct
        • Index
        • N + 1 problem
        • Normalization
        • Foreign Key
        • Relationship
        • Union & Join
        • User Defined Type
      • NOSQL (MongoDB)
      • Transaction
      • Sharding
      • Lock (Concurrency Control)
    • NodeJS
      • NodeJS vs Java Spring
      • ExpressJS
      • NestJS
        • Swagger
        • Class Validator & Validation Pipe
        • Passport (Authentication)
      • Path Module
      • Database Connection
        • Integrating with MYSQL
        • Sequalize
        • Integrating with MongoDB
        • Prisma
        • MikroORM
        • Mongoose
      • Streaming
      • Worker Thread
      • Passport JS
      • JSON Web Token
      • Socket IO
      • Bull MQ
      • Pino (Logging)
      • Yeoman
    • Spring
      • Spring MVC
      • Spring REST
      • Spring Actuator
      • Aspect Oriented Programming (AOP)
      • Controller Advice
      • Filter
      • Interceptor
      • Concurrent
      • Spring Security
      • Spring Boot
      • Spring Cloud
        • Resilience 4j
      • Quartz vs Spring Batch
      • JPA and Hibernate
      • HATEOS
      • Swagger
      • Unit Test (Java Spring)
      • Unit Test (Spring boot)
  • DevOp
    • Docker
    • Kubernetes
      • Helm
    • Nginx
    • File System
    • Cloud
      • AWS
        • EC2 (Virtual Machine)
        • Network
        • IAM
          • Role-Service Binding
        • Database
        • Route 53
        • S3
        • Message Queue
        • Application Service
        • Serverless Framework
        • Data Analysis
        • Machine Learning
        • Monitoring
        • Security
      • Azure
        • Identity
        • Compute Resource
        • Networking
        • Storage
        • Monitoring
      • Google Cloud
        • IAM
          • Workload Identity Federation
        • Compute Engine
        • VPC Network
        • Storage
        • Kubernetes Engine
        • App Engine
        • Cloud function
        • Cloud Run
        • Infra as Code
        • Pub/Sub
    • Deployment Strategy
    • Jenkins
    • Examples
      • Deploy NextJS on GCP
      • Deploy Spring on Azure
      • Deploy React on Azure
  • Domain Knowledge
    • Web 3
      • Blockchain
      • Cryptocurrency
    • AI
      • Prompt
      • Chain & Agent
      • LangChain
      • Chunking
      • Search
      • Side Products
Powered by GitBook
On this page
  • Introduction
  • Column Defintion
  • Row Model
  • Table State
  • Implementation
  • Data Fetching
  • Table Definition
  • Context Provider
  • User Interface

Was this helpful?

  1. Frontend
  2. React
  3. Table

React Table

Introduction

  • It is a headless UI library providing the logic, state, processing and API for UI elements and interactions, but do not provide markup, styles, or pre-built implementations.

  • The logic includes header grouping, column filtering (searching), column sorting, column visibility, expanding, resizing, pagination

  • Table instance is come from of data (from api), column definition, row models

Column Defintion

  • Column definition is mainly 3 types:

  • Accessor Columns (For displaying data)

  • Accessor columns have an underlying data model which means they can be sorted, filtered, grouped, etc. Display Columns (For displaying customized UI)

  • Display columns do not have a data model which means they cannot be sorted, filtered, etc, but they can be used to display arbitrary content in the table, eg. a row actions button, checkbox, expander, etc. Grouping Columns (For grouping columns into single)

  • Group columns do not have a data model so they too cannot be sorted, filtered, etc, and are used to group other columns together. It's common to define a header or footer for a column group.

const columnHelper = createColumnHelper<Person>()

// Make some columns!
const defaultColumns = [
  // Display Column
  columnHelper.display({
    id: 'actions',
    cell: props => <RowActions row={props.row} />,
  }),
  // Grouping Column
  columnHelper.group({
    header: 'Name',
    footer: props => props.column.id,
    columns: [
      // Accessor Column
      columnHelper.accessor('firstName', {
        cell: info => info.getValue(),
        footer: props => props.column.id,
      }),
      // Accessor Column
      columnHelper.accessor(row => row.lastName, {
        id: 'lastName',
        cell: info => info.getValue(),
        header: () => <span>Last Name</span>,
        footer: props => props.column.id,
      }),
    ],
  }),
  // Grouping Column
  columnHelper.group({
    header: 'Info',
    footer: props => props.column.id,
    columns: [
      // Accessor Column
      columnHelper.accessor('age', {
        header: () => 'Age',
        footer: props => props.column.id,
      }),
      // Grouping Column
      columnHelper.group({
        header: 'More Info',
        columns: [
          // Accessor Column
          columnHelper.accessor('visits', {
            header: () => <span>Visits</span>,
            footer: props => props.column.id,
          }),
          // Accessor Column
          columnHelper.accessor('status', {
            header: 'Status',
            footer: props => props.column.id,
          }),
          // Accessor Column
          columnHelper.accessor('progress', {
            header: 'Profile Progress',
            footer: props => props.column.id,
          }),
        ],
      }),
    ],
  }),
]

Row Model

  • Row models run under the hood of TanStack Table to transform your original data in useful ways that are needed for data grid features like filtering, sorting, grouping, expanding, and pagination.

import {
  getCoreRowModel,
  getExpandedRowModel,
  getFacetedMinMaxValues,
  getFacetedRowModel,
  getFacetedUniqueValues,
  getFilteredRowModel,
  getGroupedRowModel,
  getPaginationRowModel,
  getSortedRowModel,
}
//...
const table = useReactTable({
  columns,
  data,
  getCoreRowModel: getCoreRowModel(),
  getExpandedRowModel: getExpandedRowModel(),
  getFacetedMinMaxValues: getFacetedMinMaxValues(),
  getFacetedRowModel: getFacetedRowModel(),
  getFacetedUniqueValues: getFacetedUniqueValues(),
  getFilteredRowModel: getFilteredRowModel(),
  getGroupedRowModel: getGroupedRowModel(),
  getPaginationRowModel: getPaginationRowModel(),
  getSortedRowModel: getSortedRowModel(),
})

Table State

  • To get the functional state of table

  console.log("Expand", table.getState().expanded);
  // {<row index>: <isExpanded>}
  // Expand {16: true}
  console.log("Column Filter", table.getState().columnFilters);
  // [{id: <column_name>, value:<filter_value}]
  // Column Filter [{id: 'title', value: 'peter'}]
  console.log("Pagination", table.getState().pagination);
  // {pageIndex: <pageNum - 1>, pageSize: <pageSize>}
  // Pagination {pageIndex: 2, pageSize: 10}
  console.log("Sorting", table.getState().sorting);
  // [{id: <column_name>, desc: <isDescOrder>}]
  // Sorting [{id: 'id', desc: false}]
  console.log("Selection", table.getState().rowSelection);
  // {<row index>: <isSelected>}
  // Selection {16: true}

Implementation

  • Implementation, it is separated into data fetching, table definition, User interface

Data Fetching

useMyTableQuery.ts
import { useQuery } from "@tanstack/react-query";
import {
  ColumnFiltersState,
  PaginationState,
  SortingState,
} from "@tanstack/react-table";
import axios from "axios";
import { Product, productSchema } from "../../types/my-table";
interface Props {
  pagination: PaginationState;
  sorting: SortingState;
  filter: ColumnFiltersState;
}

export default function useMyTableQuery({
  pagination,
  sorting,
  filter,
}: Props) {
  return useQuery({
    queryKey: ["products", pagination],
    queryFn: async () => {
      const { data: products } = await axios.get<Product[]>(
        `https://fakestoreapi.com/products?pageIndex=${pagination.pageIndex}&pageSize=${pagination.pageSize}&sort=${sorting[0].id}:${sorting[0].desc ? "desc" : "asc"}&filter=${filter[0].id}:${filter[0].value}`,
      );
      return productSchema.array().parse(products);
    },
  });
}
my-table-ts
import { z } from "zod";

export const productSchema = z.object({
  id: z.number(),
  title: z.string(),
  price: z.number(),
  category: z.string(),
});

export type Product = z.infer<typeof productSchema>;

Table Definition

useMyTable.ts
import {
  ColumnDef,
  ColumnFiltersState,
  getCoreRowModel,
  getExpandedRowModel,
  getFilteredRowModel,
  getSortedRowModel,
  PaginationState,
  SortingState,
  useReactTable,
} from "@tanstack/react-table";
import useMyTableQuery from "./useMyTableQuery";
import { Product } from "../..//types/my-table";
const useMyTable = (columns: ColumnDef<Product, any>[]) => {
  const [pagination, setPagination] = React.useState<PaginationState>({
    pageIndex: 0,
    pageSize: 10,
  });
  const [sorting, setSorting] = React.useState<SortingState>([
    {
      id: "id",
      desc: false,
    },
  ]);
  const [filter, setFilter] = React.useState<ColumnFiltersState>([
    {
      id: "title",
      value: "",
    },
  ]);
  const { data: product } = useMyTableQuery({
    pagination,
    sorting,
    filter,
  });

  const table = useReactTable({
    defaultColumn: {
      size: 100, //starting column size
      minSize: 50, //enforced during column resizing
      maxSize: 300, //enforced during column resizing
    },
    columnResizeMode: "onChange",
    columnResizeDirection: "ltr",
    // inject data
    data: product ?? [],
    // inject column defintions
    columns,
    // inject row model
    getCoreRowModel: getCoreRowModel(),
    // insert react state into table status
    state: { pagination, sorting, columnFilters: filter },
    onPaginationChange: setPagination,
    onSortingChange: setSorting,
    onColumnFiltersChange: setFilter,
    pageCount: 10,
    manualPagination: true, // server-side
    // inject functional row model for client side handling
    // getPaginationRowModel: getPaginationRowModel() // client-side
    getSortedRowModel: getSortedRowModel(),
    // manualSorting: true,
    getFilteredRowModel: getFilteredRowModel(),
    // manualFiltering:true,
    getRowCanExpand: () => true, // Add your logic to determine 
    // if a row can be expanded. True means all rows include expanded data
    getExpandedRowModel: getExpandedRowModel(),
  });
  return { table };
};

export default useMyTable;

Context Provider

tableProvider.ts
import { Table } from "@tanstack/react-table";
import { createContext } from "react";

const TableContext = createContext<{ table: Table<any> | null }>({
  table: null,
});

export default TableContext;
useTableContext.ts
import { useContext } from "react";
import TableContext from "../../contexts/tableProvider";
import { Table } from "@tanstack/react-table";

const useTableContext = <T>() => {
  const table = useContext<{ table: Table<T> | null }>(TableContext);
  return table;
};

export default useTableContext;

User Interface

  • Container layer (Parent component)

my-table.tsx
import { createFileRoute } from "@tanstack/react-router";
import MyTable from "../../components/myTable";

export const Route = createFileRoute("/_authenticated/my-table")({
  component: () => <MyTablePage />,
});

const MyTablePage = () => {
  return (
    <MyTable>
      <MyTable.Search />
      <MyTable.Table />
      <MyTable.Pagination />
    </MyTable>
  );
};
index.tsx
import { ColumnDef, createColumnHelper } from "@tanstack/react-table";
import React from "react";
import { Product } from "../../types/my-table";
import Checkbox from "./checkBox";
import Row from "../layout/row";
import CustomTable from "./customTable";
import CustomSearch from "./customSearch";
import CustomPagination from "./customPagintaion";
import useMyTable from "../../hooks/my-table/useMyTable";
import TableContext from "../../contexts/tableProvider";

interface Props {
  children: React.ReactNode;
}
const MyTable = ({ children }: Props) => {
  const columnsHelper = createColumnHelper<Product>();
  const columns: ColumnDef<Product, any>[] = [
    columnsHelper.accessor("id", {
      header: ({ header, table }) => (
        <Row>
          <Checkbox
            {...{
              checked: table.getIsAllRowsSelected(),
              indeterminate: table.getIsSomeRowsSelected(),
              onChange: table.getToggleAllRowsSelectedHandler(),
            }}
          />
          <span>ID</span>
          <button
            onClick={() => {
              header.column.toggleSorting(
                header.column.getIsSorted() !== "desc",
              );
            }}
          >
            {{
              asc: "🔼",
              desc: "🔽",
            }[header.column.getIsSorted() as string] ?? null}
          </button>
        </Row>
      ),
      cell: ({ row, getValue }) => (
        <Row>
          <Checkbox
            {...{
              checked: row.getIsSelected(),
              indeterminate: row.getIsSomeSelected(),
              onChange: row.getToggleSelectedHandler(),
            }}
          />
          <span>{getValue()}</span>
        </Row>
      ),
      sortingFn: "alphanumeric", // use built-in sorting function by name
      sortUndefined: "last", //force undefined values to the end
    }),
    columnsHelper.accessor("title", { header: "Title" }),
    columnsHelper.accessor("price", { header: "Price" }),
    columnsHelper.accessor("category", { header: "Category" }),
    columnsHelper.display({
      id: "actions",
      cell: ({ row }) => (
        <button
          onClick={() => {
            row.getToggleExpandedHandler()();
          }}
          className="font-medium text-blue-600 dark:text-blue-500 hover:underline"
        >
          {row.getIsExpanded() ? "Collapse" : "Expand"}
        </button>
      ),
      header: "Action",
    }),
  ];
  const { table } = useMyTable(columns);

  return (
    <TableContext.Provider value={{ table }}>
      <div className="relative overflow-x-auto shadow-md sm:rounded-lg py-10 px-5">
        {children}
      </div>
    </TableContext.Provider>
  );
};
MyTable.Search = CustomSearch;
MyTable.Table = CustomTable;
MyTable.Pagination = CustomPagination;
export default MyTable;
  • Presentation Layer (Child Component)

CustomSearch.tsx
import React from "react";
import useTableContext from "../../hooks/my-table/useTableContext";
import { Product } from "../../types/my-table";

const CustomSearch = () => {
  const { table } = useTableContext<Product>();
  if (!table) return null;
  return (
    <div className="pb-4 bg-white dark:bg-gray-900">
      <label htmlFor="table-search" className="sr-only">
        Search
      </label>
      <div className="relative mt-1">
        <div className="absolute inset-y-0 rtl:inset-r-0 start-0 flex items-center ps-3 pointer-events-none">
          <svg
            className="w-4 h-4 text-gray-500 dark:text-gray-400"
            aria-hidden="true"
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 20 20"
          >
            <path
              stroke="currentColor"
              strokeLinecap="round"
              strokeLinejoin="round"
              strokeWidth="2"
              d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"
            />
          </svg>
        </div>
        <input
          type="text"
          id="table-search"
          className="block pt-2 ps-10 text-sm text-gray-900 border border-gray-300 rounded-lg w-80 bg-gray-50 focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
          placeholder="Search for items"
          onChange={(e) => {
            table.getColumn("title")?.setFilterValue(e.target.value);
          }}
        />
      </div>
    </div>
  );
};

export default CustomSearch;
CustomTable.tsx
import { flexRender } from "@tanstack/react-table";
import React from "react";
import { Product } from "../../types/my-table";
import useTableContext from "../../hooks/my-table/useTableContext";

const CustomTable = () => {
  const { table } = useTableContext<Product>();
  if (!table) return null;
  console.log("Expand", table.getState().expanded);
  console.log("Column Filter", table.getState().columnFilters);
  console.log("Pagination", table.getState().pagination);
  console.log("Sorting", table.getState().sorting);
  console.log("Selection", table.getState().rowSelection);
  console.log(table.getRowModel().rows);
  return (
    <div style={{ direction: table.options.columnResizeDirection }}>
      <table
        {...{
          style: {
            width: table.getCenterTotalSize(),
          },
        }}
        className="text-sm text-left rtl:text-right text-gray-500 dark:text-gray-400  border-solid border-2 w-fit"
      >
        <thead className="text-xs text-gray-700 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400">
          {table.getHeaderGroups().map((headerGroup) => (
            <tr key={headerGroup.id}>
              {headerGroup.headers.map((header) => (
                <th
                  key={header.id}
                  scope="col"
                  className={`p-4 relative`}
                  style={{ width: `${header.getSize()}px` }}
                  colSpan={header.colSpan}
                >
                  {header.isPlaceholder
                    ? null
                    : flexRender(
                        header.column.columnDef.header,
                        header.getContext(),
                      )}
                  <div
                    className={`border-4 resizer ${
                      table.options.columnResizeDirection
                    } ${header.column.getIsResizing() ? "isResizing" : ""}`}
                    {...{
                      onDoubleClick: () => header.column.resetSize(),
                      onMouseDown: header.getResizeHandler(),
                      onTouchStart: header.getResizeHandler(),
                    }}
                  />
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody>
          {table.getRowModel().rows.map((row) => (
            <React.Fragment key={row.id}>
              <tr className="bg-white border-b dark:bg-gray-800 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-600">
                {row.getVisibleCells().map((cell) => (
                  <td
                    className={`p-4 `}
                    style={{ width: `${cell.column.getSize()}px` }}
                    key={cell.id}
                  >
                    {flexRender(cell.column.columnDef.cell, cell.getContext())}
                  </td>
                ))}
              </tr>
              {row.getIsExpanded() && (
                <tr>
                  <td colSpan={row.getAllCells().length}>
                    {row.getValue("title")}
                  </td>
                </tr>
              )}
            </React.Fragment>
          ))}
        </tbody>
      </table>
    </div>
  );
};

export default CustomTable;
CustomPagination.tsx
import React from "react";
import useTableContext from "../../hooks/my-table/useTableContext";
import { Product } from "../../types/my-table";

const CustomPagination = () => {
  const { table } = useTableContext<Product>();
  if (!table) return null;
  const getPagination = (totalPages: number, currentPage: number): number[] => {
    const pageNumbers = [];
    const maxVisiblePages = 5;
    const halfVisible = Math.floor(maxVisiblePages / 2);

    let startPage = Math.max(1, currentPage - halfVisible);
    let endPage = Math.min(totalPages, currentPage + halfVisible);

    if (endPage - startPage < maxVisiblePages - 1) {
      if (startPage === 1) {
        endPage = Math.min(totalPages, startPage + maxVisiblePages - 1);
      } else if (endPage === totalPages) {
        startPage = Math.max(1, endPage - maxVisiblePages + 1);
      }
    }

    for (let i = startPage; i <= endPage; i++) {
      pageNumbers.push(i);
    }

    return pageNumbers;
  };
  const currentPage = table.getState().pagination.pageIndex + 1;
  return (
    <nav
      className="flex items-center flex-column flex-wrap md:flex-row justify-between pt-4"
      aria-label="Table navigation"
    >
      <span className="text-sm font-normal text-gray-500 dark:text-gray-400 mb-4 md:mb-0 block w-full md:inline md:w-auto">
        Page of{" "}
        <span className="font-semibold text-gray-900 dark:text-white">
          {table.getState().pagination.pageIndex + 1}
        </span>{" "}
        of{" "}
        <span className="font-semibold text-gray-900 dark:text-white">
          {table.getPageCount()}
        </span>
      </span>
      <ul className="inline-flex -space-x-px rtl:space-x-reverse text-sm h-8">
        <li>
          <button
            className="flex items-center justify-center px-3 h-8 ms-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-s-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
            onClick={() => {
              table.setPageIndex(0);
            }}
          >
            {"<<"}
          </button>
        </li>
        <li>
          <button
            disabled={!table.getCanPreviousPage()}
            onClick={() => {
              table.previousPage();
            }}
            className="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
          >
            {"<"}
          </button>
        </li>
        {getPagination(table.getPageCount(), currentPage).map((pageNum) => (
          <li key={pageNum}>
            <button
              className={`${currentPage === pageNum ? "  font-bold" : ""} flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white`}
              onClick={() => {
                table.setPageIndex(pageNum - 1);
              }}
            >
              {pageNum}
            </button>
          </li>
        ))}
        <li>
          <button
            className="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
            disabled={!table.getCanNextPage()}
            onClick={() => {
              table.nextPage();
            }}
          >
            {">"}
          </button>
        </li>
        <li>
          <button
            disabled={!table.getCanNextPage()}
            className="flex items-center justify-center px-3 h-8 leading-tight text-gray-500 bg-white border border-gray-300 rounded-e-lg hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white"
            onClick={() => {
              table.setPageIndex(table.getPageCount() - 1);
            }}
          >
            {">>"}
          </button>
        </li>
      </ul>
      <select
        className="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
        value={table.getState().pagination.pageSize}
        onChange={(e) => {
          console.log(e.target.value);
          table.setPageSize(Number(e.target.value));
        }}
      >
        {[10, 20, 30, 40, 50].map((pageSize) => (
          <option key={pageSize} value={pageSize}>
            Show {pageSize}
          </option>
        ))}
      </select>
    </nav>
  );
};

export default CustomPagination;
Checkbox.tsx
import React, { HTMLProps } from "react";

function Checkbox({
  indeterminate,
  className = "",
  ...rest
}: { indeterminate?: boolean } & HTMLProps<HTMLInputElement>) {
  const ref = React.useRef<HTMLInputElement>(null!);

  React.useEffect(() => {
    if (typeof indeterminate === "boolean") {
      ref.current.indeterminate = !rest.checked && indeterminate;
    }
  }, [ref, indeterminate, rest.checked]);

  return (
    <input
      type="checkbox"
      ref={ref}
      className={
        className +
        "w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 dark:focus:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600  cursor-pointer"
      }
      {...rest}
    />
  );
}

export default Checkbox;

PreviousTableNextForm & Validation

Last updated 6 months ago

Was this helpful?