React – shadcn/ui の Table コンポーネントについて解説

概要

shadcn/ui の Table コンポーネントの使い方について解説します。 このコンポーネントは、React アプリケーションで静的または動的なテーブルを簡単に作成するためのコンポーネントです。

インストール方法

まず、shadcn/ui ライブラリから Table コンポーネントをインストールします。以下のコマンドを使用します。 このコマンドを実行すると、Table コンポーネントが src/components/ui/table.tsx にインストールされます。

npx shadcn@latest add table
Bash

Table コンポーネントの実装

src/components/ui/table.tsx には以下の複数のコンポーネントが定義されています。 細かい調整は、使用する際に className を指定するか、このファイルを編集して行います。

  • Table: <table> に相当
  • TableHeader: <thead> に相当
  • TableBody: <tbody> に相当
  • TableFooter: <tfoot> に相当
  • TableRow: <tr> に相当
  • TableHead: <th> に相当
  • TableCell: <td> に相当
  • TableCaption: <caption> に相当

文字は背景色の設定は src/index.css ファイルを編集することで行います。

  • --muted-foreground: キャプチャ、ヘッダの文字色
  • --muted: ホバー、選択した行の背景色
src/index.css
:root {
    // ...
    --muted-foreground: #6b7280; /* グレー */
    --muted: #f9fafb; /* 非アクティブな行の背景色 */
    // ...
}
CSS

静的なテーブルを作成する

ここでは、Table コンポーネントを使用して静的なテーブルを作成する方法について説明します。 以下は、商品の一覧を表示する簡単なテーブルの例です。

src/product/product-table.tsx
import {
  Table,
  TableBody,
  TableCaption,
  TableCell,
  TableFooter,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";

const ProductTable = () => {
  return (
    <Table>
      {/* Caption */}
      <TableCaption>商品の一覧</TableCaption>
      {/* Header */}
      <TableHeader>
        <TableRow>
          <TableHead>商品名</TableHead>
          <TableHead>値段</TableHead>
        </TableRow>
      </TableHeader>
      {/* Body */}
      <TableBody>
        <TableRow>
          <TableCell>商品A</TableCell>
          <TableCell className="text-right">¥2,500</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>商品B</TableCell>
          <TableCell className="text-right">¥3,000</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>商品C</TableCell>
          <TableCell className="text-right">¥1,500</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>商品D</TableCell>
          <TableCell className="text-right">¥4,200</TableCell>
        </TableRow>
        <TableRow>
          <TableCell>商品E</TableCell>
          <TableCell className="text-right">¥2,800</TableCell>
        </TableRow>
      </TableBody>
      {/* Footer */}
      <TableFooter>
        <TableRow>
          <TableCell>合計</TableCell>
          <TableCell className="text-right">¥14,000</TableCell>
        </TableRow>
      </TableFooter>
    </Table>
  );
};

export default ProductTable;
React TSX

次に、このテーブルコンポーネントをアプリケーションに組み込みます。

src/App.tsx
import ProductTable from "@/product/product-table";

function App() {
  return (
    <>
      <div className="mx-auto px-6 py-12 container">
        <ProductTable />
      </div>
    </>
  );
}

export default App;
React TSX

動的なテーブルを作成する

TanStack Table を使用して、動的なテーブルを作成するサンプルです。

1. TanStack をインストール

npm install @tanstack/react-table
Bash

2. カラムの定義

src/payment ディレクトリを作成し、その配下に以下の 2 つのファイルを作成します。

  • src/payment/columns.tsx: カラムの定義
  • src/payment/data.tsx: テーブルの実装

カラムは、TanStack Table の ColumnDef 型の配列として、定義します。

src/payment/columns.tsx
import { ColumnDef } from "@tanstack/react-table";

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",
  },
];
React TSX

解説:

データの配列の要素のインタフェースを定義しています。

export type Payment = {
  id: string;
  amount: number;
  status: "pending" | "processing" | "success" | "failed";
  email: string;
};
React TSX

テーブルに表示するカラムの定義を行っています。

  • accessorKey: 渡された配列の各要素で、データにアクセスするために使用されるプロパティ名
  • header: ヘッダの表示名
export const columns: ColumnDef<Payment>[] = [
  {
    accessorKey: "status",
    header: "Status",
  },
  {
    accessorKey: "email",
    header: "Email",
  },
  {
    accessorKey: "amount",
    header: "Amount",
  },
];
React TSX

3. テーブルの実装

次に、動的なテーブルの実装を行います。以下は、src/payment/payment-table.tsx の内容です。 プロパティとして、カラムの定義 columns とデータ data を受け取ります。

src/payment/payment-table.tsx
import {
  ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";

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

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

export function PaymentTable<TData, TValue>({
  columns,
  data,
}: PaymentTableProps<TData, TValue>) {
  const table = useReactTable({
    data,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  return (
    <div className="border rounded-md">
      <Table>
        {/* Header */}
        <TableHeader>
          {table.getHeaderGroups().map((headerGroup) => (
            <TableRow key={headerGroup.id}>
              {headerGroup.headers.map((header) => (
                <TableHead key={header.id}>
                  {header.isPlaceholder
                    ? null
                    : flexRender(
                        header.column.columnDef.header,
                        header.getContext()
                      )}
                </TableHead>
              ))}
            </TableRow>
          ))}
        </TableHeader>

        {/* Body */}
        <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">
                データなし
              </TableCell>
            </TableRow>
          )}
        </TableBody>
      </Table>
    </div>
  );
}
React TSX

解説:

useReactTable フックを使用して、テーブルを作成します。

const table = useReactTable({
  data,
  columns,
  getCoreRowModel: getCoreRowModel(),
});
React TSX

table.getHeaderGroups() を使用してヘッダ情報を取得し、テーブルのヘッダを作成します。

<TableHeader>
  {table.getHeaderGroups().map((headerGroup) => (
    <TableRow key={headerGroup.id}>
      {headerGroup.headers.map((header) => (
        <TableHead key={header.id}>
          {header.isPlaceholder
            ? null
            : flexRender(header.column.columnDef.header, header.getContext())}
        </TableHead>
      ))}
    </TableRow>
  ))}
</TableHeader>
React TSX
  • API
    • HeaderGroup: 複数のヘッダから成るヘッダグループ
    • Header: 複数のカラムから成るヘッダ
    • Column: カラム
    • ColumnDef: カラムの定義

table.getRowModel() を使用してデータを取得し、テーブルのボディを作成します。 データが存在しない場合は、「データなし」と表示します。

<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">
        データなし
      </TableCell>
    </TableRow>
  )}
</TableBody>
React TSX

コメント

コメントする