CatalystUI

DocsTemplate

Table

A component to visualize data in tabular format.

Sales by country
CountrySalesValueBounce
United States2,500$230,90029.9
India3,900$440,00040.22
Germany1,400$190,70023.44
Brasil562$30,90032.14
Britain1,627$143,96019.2
China33,023$100,22333.3

Installations

Install clsx, and tailwind-merge to use avatar component.

npm install clsx tailwind-merge

Add the following function in lib/utils

import clsx, { type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
 
export function cx(...args: ClassValue[]) {
  return twMerge(clsx(...args));
}

Copy paste the component

import React, { ReactElement, ReactNode } from "react";
 
import { cx } from "@/lib/utils";
 
function TableRoot({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactElement;
}) {
  return (
    <div>
      <div
        // scrol on mobile
        className={cx("w-full overflow-auto whitespace-nowrap", className)}
        {...props}
      >
        {children}
      </div>
    </div>
  );
}
TableRoot.displayName = "Table";
 
function Table({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <table
      className={cx(
        // base
        "w-full caption-bottom border-b",
        // border color
        "border-gray-200 dark:border-gray-800",
        className
      )}
      {...props}
    >
      {children}
    </table>
  );
}
Table.displayName = "Table";
 
function TableHead({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <thead className={cx(className)} {...props}>
      {children}
    </thead>
  );
}
TableHead.displayName = "TableHead";
 
function TableHeaderCell({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <th
      className={cx(
        // base
        "border-b px-4 py-3.5 text-left text-sm font-semibold",
        // text-color
        "text-gray-900 dark:text-gray-50",
        // border color
        "border-gray-200 dark:border-gray-800",
        className
      )}
      {...props}
    >
      {children}
    </th>
  );
}
TableHeaderCell.displayName = "TableHead";
 
function TableBody({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <tbody
      className={cx(
        // base
        "divide-y",
        // divide color
        "divide-gray-200 dark:divide-gray-800",
        className
      )}
      {...props}
    >
      {children}
    </tbody>
  );
}
TableBody.displayName = "TableBody";
 
function TableRow({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <tr
      className={cx(
        "[&_td:last-child]:pr-4 [&_th:last-child]:pr-4",
        "[&_td:first-child]:pl-4 [&_th:first-child]:pl-4",
        className
      )}
      {...props}
    >
      {children}
    </tr>
  );
}
TableRow.displayName = "TableRow";
 
function TableData({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <td
      className={cx(
        //base
        "p-4 text-sm",
        // text color
        "text-gray-600 dark:text-gray-400",
        className
      )}
      {...props}
    >
      {children}
    </td>
  );
}
TableData.displayName = "TableData";
 
function TableFoot({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <tfoot
      className={cx(
        // base
        "border-t text-left font-medium",
        // text color
        "text-gray-900 dark:text-gray-50",
        // border color
        "border-gray-200 dark:border-gray-800",
        className
      )}
      {...props}
    >
      {children}
    </tfoot>
  );
}
TableFoot.displayName = "TableFoot";
 
function TableCaption({
  className,
  children,
  ...props
}: {
  className?: string;
  children: ReactNode;
}) {
  return (
    <caption
      className={cx(
        // base
        "mt-3 px-3 text-center text-sm",
        // text color
        "text-gray-500 dark:text-gray-500",
        className
      )}
      {...props}
    >
      {children}
    </caption>
  );
}
TableCaption.displayName = "TableCaption";
 
export {
  TableRoot,
  Table,
  TableHead,
  TableHeaderCell,
  TableRow,
  TableData,
  TableBody,
  TableFoot,
  TableCaption,
};

Usage

import {
  Table,
  TableBody,
  TableCaption,
  TableData,
  TableHead,
  TableHeaderCell,
  TableRoot,
  TableRow,
} from "@/library/components/ui/table";
 
const tableData = [
  {
    id: 1,
    country: "United States",
    sales: 2500,
    value: 230900,
    bounce: 29.9,
  },
  ...
];
 
export default function TableView() {
  return (
    <CardRoot>
      <TableRoot>
        <Table>
          <TableCaption>Sales by country</TableCaption>
          <TableHead>
            <TableRow>
              <TableHeaderCell>Country</TableHeaderCell>
              <TableHeaderCell>Sales</TableHeaderCell>
              <TableHeaderCell>Value</TableHeaderCell>
              <TableHeaderCell>Bounce</TableHeaderCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {tableData.map((data) => (
              <TableRow key={data.id}>
                <TableData>{data.country}</TableData>
                <TableData>{data.sales.toLocaleString("en-US")}</TableData>
                <TableData>${data.value.toLocaleString("en-US")}</TableData>
                <TableData>{data.bounce}</TableData>
              </TableRow>
            ))}
          </TableBody>
        </Table>
      </TableRoot>
    </CardRoot>
  );
}

Next: Line Chart

Found a bug? Report here.