Table

    To get the best performance we are using react-table behind the scenes with shadcn DataTable if you ever need more in depth examples follow their docs.

    Table Types

    Static Table

    1. Define Table Columns
      • Create a folder _components page under /src/app/dashboard/page-name
      • Create a file called columns.tsx

    /src/app/dashboard/page-name/_components/columns.tsx

    "use client";
    
    import { ColumnDef } from "@tanstack/react-table";
    
    // Example User type
    type User = { id: string; name: string; email: string };
    
    export const columns: ColumnDef<User>[] = [
      {
        // the object key of User type object
        accessorKey: "id",
        // (optional) the title of the header (returns value or react component)
        header: "ID",
        // (optional) the size of the column in pixels
        size: 80,
      },
      {
        // the object key of User type object
        accessorKey: "name",
        // (optional) the title of the header (returns value or react component)
        header: "Name",
        // (optional) use the cell property to modify the value of the key name
        // (returns value or react component)
        cell: ({ row: { original } }) => (
          <p className="text-xs">{original.name.toUpperCase()}</p>
        ),
      },
      {
        // the object key of User type object
        accessorKey: "email",
        // (optional) the title of the header (returns value or react component)
        header: "Email",
      },
    ];
    
    1. Create a table using react-table also under _components

    /src/app/dashboard/page-name/_components/table.tsx

    "use client";
    
    import { DataTable } from "components/table/data-table";
    import { columns } from "./columns";
    import { getCoreRowModel, useReactTable } from "@tanstack/react-table";
    
    // List of users
    const data: User[] = [
      { id: 0, name: "Joe", email: "joe@email.com" },
      { id: 1, name: "Dave", email: "dave@email.com" },
    ];
    
    const Table = () => {
      // create the react-table using useReactTable hook
      // pass the data, columns, getCoreRowModel
      const table = useReactTable({
        data,
        columns,
        getCoreRowModel: getCoreRowModel(),
      });
    
      return (
        <DataTable
          // pass the table object here
          table={table}
          // accepts a flag to show a spinner instead of data
          isFetching={false}
          // navigate to a specific path on row click
          // add the key you want to use in the User object between brackets in this case "/dashboard/users/[id]"
          // it also accepts dot notation key { user: { id: 0 } } -> "/dashboard/users/[user.id]"
          navigateTo="/dashboard/users/[id]"
        />
      );
    };
    
    export default Table;
    
    1. Use the table in your page.tsx

    /src/app/dashboard/page-name/page.tsx

    import Table from "./_components/table";
    
    const ExamplePage = () => {
      return <Table />;
    };
    
    export default ExamplePage;
    

    Filterable Table

    1. Create only columns.tsx as you did before
    2. Create query-fields.tsx in _components

    /src/app/dashboard/page-name/_components/query-fields.tsx

    "use client";
    
    import DataTableQueryFields from "components/table/data-table-query-fields";
    import { useFilteredTableContext } from "components/table/filtered-data-table";
    import { Input } from "components/ui/input";
    import { useSearchParams } from "next/navigation";
    
    const QueryFields = () => {
      const searchParams = useSearchParams();
      // queryChangeHandler updates the searchParams
      const { queryChangeHandler } = useFilteredTableContext();
    
      return (
        // DataTableQueryFields is just styled element
        <DataTableQueryFields>
          {/* Add an input element */}
          <Input
            placeholder="name"
            // make sure to decode the URI so we don't get encoded characters
            defaultValue={decodeURIComponent(searchParams.get("name") || "")}
            // listen onChange to update the query when you type
            onChange={(e) => queryChangeHandler({ id: e.target.value })}
          />
        </DataTableQueryFields>
      );
    };
    
    export default QueryFields;
    
    1. In your page.tsx

    /src/app/dashboard/page-name/page.tsx

    import { Prisma } from "@prisma/client";
    import FilteredDataTable from "components/table/filtered-data-table";
    import { db } from "lib/db";
    import { PropsWithParams } from "types";
    import { FC } from "react";
    import { columns } from "./_components/columns";
    import QueryFields from "./_components/query-fields";
    
    const Reviews: FC<PropsWithParams> = async ({ searchParams }) => {
      const searchParams = await searchParams;
      const {
        // add default values to all keys
        name = "",
        // limit and page are added automatically to searchParams
        limit = 10,
        page = 0,
      } = searchParams;
      // Create a unified where input to use to count the rows and the find query
      const where: Prisma.UserWhereInput = { name };
      const rowCount = await db.productReview.count({ where });
      // make sure page and limit are number
      const pageAsNumber = Number(page);
      const limitAsNumber = Number(limit);
      // fetch the users
      const users = await db.user.findMany({
        where,
        // important for pagination
        skip: pageAsNumber * limitAsNumber,
        take: pageAsNumber <= 0 ? limitAsNumber : pageAsNumber * limitAsNumber,
      });
    
      return (
        <FilteredDataTable columns={columns} data={reviews} rowCount={rowCount}>
          <ReviewsQueryFields />
        </FilteredDataTable>
      );
    };
    
    export default Reviews;