データテーブルDataTableBeta

列定義、絞り込み、ページ送りを組み合わせて行データを表示するテーブルです。

プレビュー

1 - 10 / 全18件
青井 花owner · active2024-01-15
田中 空admin · active2024-03-08
山本 優member · invited2025-04-22
小林 真央member · active2024-06-30
中村 蓮admin · suspended2024-11-04
佐藤 葵member · active2025-02-12
鈴木 凛member · active2025-06-18
高橋 海member · invited2025-08-01
伊藤 碧admin · active2025-09-20
渡辺 陽member · suspended2025-10-11

状態とバリエーション

行クリック

onRowClick で行全体をクリック(またはフォーカス時に Enter)で開けます。行内のボタンなどインタラクティブ要素のクリックは行クリックを発火しません。

1 - 4 / 4
青井 花owner
田中 空admin
山本 優member
小林 真央member
1 / 1

行クリック: / 詳細ボタン:

バッジ付きセル

セル内では Badge や Button などの GunjoUI コンポーネントを組み合わせられます。

1 - 10 / 全18件
青井 花所有者有効2024-01-15
田中 空管理者有効2024-03-08
山本 優メンバー招待中2025-04-22
小林 真央メンバー有効2024-06-30
中村 蓮管理者停止中2024-11-04
佐藤 葵メンバー有効2025-02-12
鈴木 凛メンバー有効2025-06-18
高橋 海メンバー招待中2025-08-01
伊藤 碧管理者有効2025-09-20
渡辺 陽メンバー停止中2025-10-11

空状態

データがない場合は、テーブル内に空状態の行を表示します。

0 - 0 / 全0件
該当する結果がありません。
1 / 1

絞り込みなし

一覧が短い場合や外部フィルターを使う場合は、テーブル内の検索入力を非表示にします。

1 - 10 / 全10件
青井 花所有者有効2024-01-15
田中 空管理者有効2024-03-08
山本 優メンバー招待中2025-04-22
小林 真央メンバー有効2024-06-30
中村 蓮管理者停止中2024-11-04
佐藤 葵メンバー有効2025-02-12
鈴木 凛メンバー有効2025-06-18
高橋 海メンバー招待中2025-08-01
伊藤 碧管理者有効2025-09-20
渡辺 陽メンバー停止中2025-10-11
1 / 1

列に TanStack の footer を定義すると、テーブル下部に合計行(<tfoot>)が出ます。合計は「フィルタ後の全行」で計算するので、表示中のページだけでなく絞り込み結果に一致します。金額を編集すると合計が追従します。card モード(renderCard)では出ないので、その場合は合計をカード外に置いてください。

1 - 3 / 3
請求内訳
初期設定サポート1
月額プラン3
追加ストレージ2
合計6¥55,000
1 / 1

金額を編集すると合計行が追従します。

プロパティ

表は横にスクロールできます
プロパティ初期値説明
columnsColumnDef<TData, TValue>[]-行データをどう表示するかを定義する列設定です。
dataTData[]-テーブルに表示する行データです。
columns[].footerColumnDef['footer']-いずれかの列に TanStack の footer を定義すると、合計行(<tfoot>)を表示します。footer(({ table }) => …) で getFilteredRowModel() を使うとフィルタ後の合計になります。card モードでは表示されません。(#255)
filter{ columnId: string; placeholder?: string } | nullundefined指定した列を絞り込む入力欄を表示します。null で非表示にします。
pageSizenumber101ページに表示する行数です。
pageSizeOptionsnumber[][10, 25, 50, 100, 200]ページネーションで選べる表示件数です。
labelsDataTableLabels-検索、空状態、並び替え、ページネーションの文言を差し替えます。
onRowClick(row: TData) => void-指定すると各行がフォーカス可能・アクティブ化可能になり、クリック/Enter で呼ばれます。行内のインタラクティブ要素(ボタン等)のクリックは除外されます。
renderCard(row: TData) => ReactNode-モバイル(< md)で行をカードのスタックとして表示します。onRowClick 指定時はカード自体が role="button" になるため、非インタラクティブな内容を返すこと(カード全体をタップ可能にするには onRowClick を使い、カードのルートに自前の button/a を置かない)。行内の小さな操作ボタンは可。関数propのため Client Component からのみ渡すこと。(#333/#338)
captionReact.ReactNode-テーブルの <caption>(アクセシブル名)。複数テーブルがある画面で screen reader が区別できます。既定は可視、captionClassName="sr-only" で読み上げ専用に。(#298)
aria-label / aria-labelledbystring-可視 caption が無いとき <table> に名前を付けます。既存の見出し(CardTitle 等)の id を指す aria-labelledby を推奨。(#298)
hidePaginationSummaryboolean-ページネーション見出しの「1 - 4 / 4」サマリを隠します。狭いホスト(例: 約420px のマスター列)向け。ページャは自動で下段に折り返します。(#311)
classNamestring-ラッパーに追加するクラスです。

使い方

import type { ColumnDef } from "@tanstack/react-table"
import { Badge, DataTable, type DataTableLabels } from "@gunjo/ui"

type Member = {
  id: string
  name: string
  role: "owner" | "admin" | "member"
  status: "active" | "invited" | "suspended"
  joinedAt: string
}

const members: Member[] = [
  { id: "1", name: "青井 花", role: "owner", status: "active", joinedAt: "2024-01-15" },
  { id: "2", name: "田中 空", role: "admin", status: "active", joinedAt: "2024-03-08" },
  { id: "3", name: "山本 優", role: "member", status: "invited", joinedAt: "2025-04-22" },
  { id: "4", name: "小林 真央", role: "member", status: "active", joinedAt: "2024-06-30" },
  { id: "5", name: "中村 蓮", role: "admin", status: "suspended", joinedAt: "2024-11-04" },
  { id: "6", name: "佐藤 葵", role: "member", status: "active", joinedAt: "2025-02-12" },
  { id: "7", name: "鈴木 凛", role: "member", status: "active", joinedAt: "2025-06-18" },
  { id: "8", name: "高橋 海", role: "member", status: "invited", joinedAt: "2025-08-01" },
  { id: "9", name: "伊藤 碧", role: "admin", status: "active", joinedAt: "2025-09-20" },
  { id: "10", name: "渡辺 陽", role: "member", status: "suspended", joinedAt: "2025-10-11" },
  { id: "11", name: "加藤 澪", role: "member", status: "active", joinedAt: "2025-12-03" },
  { id: "12", name: "森 七海", role: "member", status: "active", joinedAt: "2026-01-09" },
  { id: "13", name: "石井 悠", role: "admin", status: "active", joinedAt: "2026-02-14" },
  { id: "14", name: "清水 旭", role: "member", status: "invited", joinedAt: "2026-03-07" },
  { id: "15", name: "林 彩", role: "member", status: "active", joinedAt: "2026-04-16" },
  { id: "16", name: "井上 湊", role: "member", status: "suspended", joinedAt: "2026-05-02" },
  { id: "17", name: "木村 詩", role: "member", status: "active", joinedAt: "2026-05-10" },
  { id: "18", name: "斎藤 光", role: "member", status: "active", joinedAt: "2026-05-21" },
]

const roleLabels: Record<Member["role"], string> = {
  owner: "所有者",
  admin: "管理者",
  member: "メンバー",
}

const statusLabels: Record<Member["status"], string> = {
  active: "有効",
  invited: "招待中",
  suspended: "停止中",
}

const statusVariants: Record<Member["status"], "default" | "secondary" | "destructive"> = {
  active: "default",
  invited: "secondary",
  suspended: "destructive",
}

const columns: ColumnDef<Member>[] = [
  {
    accessorKey: "name",
    header: "名前",
    cell: ({ row }) => <span className="font-medium">{row.original.name}</span>,
  },
  {
    accessorKey: "role",
    header: "権限",
    cell: ({ row }) => roleLabels[row.original.role],
  },
  {
    accessorKey: "status",
    header: "状態",
    cell: ({ row }) => {
      const status = row.original.status
      return <Badge variant={statusVariants[status]}>{statusLabels[status]}</Badge>
    },
  },
  { accessorKey: "joinedAt", header: "参加日" },
]

const labels: DataTableLabels = {
  filterPlaceholder: "名前で絞り込み...",
  noResults: "該当する結果がありません。",
  previous: "前へ",
  next: "次へ",
  rowsPerPage: "表示件数",
  pageSizeOption: (size) => size + "件",
}

export function MembersTable() {
  return (
    <DataTable
      columns={columns}
      data={members}
      filter={{ columnId: "name", placeholder: labels.filterPlaceholder }}
      labels={labels}
      pageSize={10}
      pageSizeOptions={[10, 25, 50, 100, 200]}
    />
  )
}

使用コンポーネント