アクション付きデータテーブルActionDataTableExperimental

行選択、一括操作、行操作を組み合わせたデータテーブルです。

プレビュー

1 - 10 / 全300件
0選択中
行操作
春の新生活バナー青井 花公開中2026-05-28
アプリ訴求 LP田中 空下書き2026-05-27
法人向け資料広告山本 優公開中2026-05-26
旧キャンペーン素材小林 真央保管済み2026-05-25
展示会フォロー中村 蓮下書き2026-05-24
採用サイト告知佐藤 葵公開中2026-05-23
店舗向け予約導線伊藤 陽公開中2026-05-22
夏季キャンペーン高橋 澪下書き2026-05-21
資料請求リターゲティング渡辺 凛公開中2026-05-20
法人向けメール施策加藤 蒼保管済み2026-05-19

状態とバリエーション

選択と一括操作

行を選択すると一括操作が有効になり、未選択時は理由をツールチップで説明します。

1 - 10 / 全300件
0選択中
行操作
春の新生活バナー青井 花公開中2026-05-28
アプリ訴求 LP田中 空下書き2026-05-27
法人向け資料広告山本 優公開中2026-05-26
旧キャンペーン素材小林 真央保管済み2026-05-25
展示会フォロー中村 蓮下書き2026-05-24
採用サイト告知佐藤 葵公開中2026-05-23
店舗向け予約導線伊藤 陽公開中2026-05-22
夏季キャンペーン高橋 澪下書き2026-05-21
資料請求リターゲティング渡辺 凛公開中2026-05-20
法人向けメール施策加藤 蒼保管済み2026-05-19

行操作

各行の操作は右端に固定し、無効な行操作は理由をツールチップで表示します。

1 - 10 / 全300件
0選択中
行操作
春の新生活バナー青井 花公開中2026-05-28
アプリ訴求 LP田中 空下書き2026-05-27
法人向け資料広告山本 優公開中2026-05-26
旧キャンペーン素材小林 真央保管済み2026-05-25
展示会フォロー中村 蓮下書き2026-05-24
採用サイト告知佐藤 葵公開中2026-05-23
店舗向け予約導線伊藤 陽公開中2026-05-22
夏季キャンペーン高橋 澪下書き2026-05-21
資料請求リターゲティング渡辺 凛公開中2026-05-20
法人向けメール施策加藤 蒼保管済み2026-05-19

プロパティ

表は横にスクロールできます
プロパティ初期値説明
columnsColumnDef<TData, TValue>[]-表示列です。選択列と行操作列は ActionDataTable が追加します。
dataTData[]-表示する行データです。
getRowId(row: TData, index: number) => string-選択状態を維持するための安定した行 ID を返します。
getRowLabel(row: TData, index: number) => string-行選択チェックボックスのアクセシブル名に使うラベルです。
enableSelectionbooleantrue行選択列を表示するかどうかです。
rowActionsActionDataTableRowAction<TData>[]-各行の右端に表示する操作です。無効理由はツールチップで説明します。
bulkActionsActionDataTableBulkAction<TData>[]-選択行に対して実行する一括操作です。
labelsActionDataTableLabels-DataTable の文言に加えて、選択・一括操作・行操作の文言を差し替えます。

使い方

"use client"

import * as React from "react"
import type { ColumnDef } from "@tanstack/react-table"
import { IconArchive, IconPencil, IconTrash } from "@tabler/icons-react"
import { ActionDataTable, Badge, type ActionDataTableLabels } from "@gunjo/ui"

type Campaign = {
  id: string
  name: string
  owner: string
  status: "active" | "draft" | "archived"
  updatedAt: string
}

const campaigns: Campaign[] = [
  { id: "c-001", name: "春の新生活バナー", owner: "青井 花", status: "active", updatedAt: "2026-05-12" },
  { id: "c-002", name: "アプリ訴求 LP", owner: "田中 空", status: "draft", updatedAt: "2026-05-10" },
  { id: "c-003", name: "法人向け資料広告", owner: "山本 優", status: "active", updatedAt: "2026-05-08" },
  { id: "c-004", name: "旧キャンペーン素材", owner: "小林 真央", status: "archived", updatedAt: "2026-04-28" },
  { id: "c-005", name: "展示会フォロー", owner: "中村 蓮", status: "draft", updatedAt: "2026-04-25" },
]

const statusLabels: Record<Campaign["status"], string> = {
  active: "公開中",
  draft: "下書き",
  archived: "保管済み",
}

const statusVariants: Record<Campaign["status"], "default" | "secondary" | "outline"> = {
  active: "default",
  draft: "secondary",
  archived: "outline",
}

const columns: ColumnDef<Campaign>[] = [
  {
    accessorKey: "name",
    header: "キャンペーン",
    size: 280,
    cell: ({ row }) => <span className="font-medium">{row.original.name}</span>,
  },
  { accessorKey: "owner", header: "担当者", size: 128 },
  {
    accessorKey: "status",
    header: "状態",
    size: 112,
    cell: ({ row }) => {
      const status = row.original.status
      return <Badge variant={statusVariants[status]}>{statusLabels[status]}</Badge>
    },
  },
  { accessorKey: "updatedAt", header: "更新日", size: 120 },
]

const labels: ActionDataTableLabels = {
  filterPlaceholder: "キャンペーン名で絞り込み...",
  noResults: "該当するキャンペーンがありません。",
  previous: "前へ",
  next: "次へ",
  rowsPerPage: "表示件数",
  selectedRows: (count) => count + "件を選択中",
  selectedRowsLabel: "選択中",
  selectAllRows: "すべての行を選択します",
  selectRow: (label) => label + "を選択します",
  selectAllRowsSelected: "すべての選択を外します",
  selectRowSelected: (label) => label + "の選択を外します",
  clearSelection: "選択を解除",
  actions: "行操作",
  bulkActions: "一括操作",
  bulkActionPlaceholder: "一括操作",
  disabledAction: "行を選択すると操作できます",
}

export function CampaignTable() {
  const [rows, setRows] = React.useState(campaigns)

  const archiveRows = (selectedRows: Campaign[]) => {
    const selectedIds = new Set(selectedRows.map((row) => row.id))
    setRows((current) =>
      current.map((row) =>
        selectedIds.has(row.id)
          ? { ...row, status: "archived", updatedAt: "2026-05-22" }
          : row
      )
    )
  }

  const deleteRows = (selectedRows: Campaign[]) => {
    const selectedIds = new Set(selectedRows.map((row) => row.id))
    setRows((current) => current.filter((row) => !selectedIds.has(row.id)))
  }

  return (
    <ActionDataTable
      columns={columns}
      data={rows}
      filter={{ columnId: "name", placeholder: labels.filterPlaceholder }}
      labels={labels}
      getRowId={(row) => row.id}
      getRowLabel={(row) => row.name}
      rowActions={[
        {
          id: "edit",
          label: "編集",
          icon: IconPencil,
          onSelect: (row) => window.alert(row.name + "を編集します"),
        },
        {
          id: "archive",
          label: "保管",
          icon: IconArchive,
          disabled: (row) => row.status === "archived",
          disabledReason: "すでに保管済みです",
          onSelect: (row) => archiveRows([row]),
        },
        {
          id: "delete",
          label: "削除",
          icon: IconTrash,
          variant: "destructive",
          disabled: (row) => row.status === "archived",
          disabledReason: "保管済みの行はこの画面から削除できません",
          onSelect: (row) => deleteRows([row]),
        },
      ]}
      bulkActions={[
        {
          id: "archive",
          label: "保管",
          icon: IconArchive,
          disabledReason: "行を選択すると保管できます",
          onSelect: archiveRows,
        },
        {
          id: "delete",
          label: "削除",
          icon: IconTrash,
          variant: "destructive",
          disabledReason: "行を選択すると削除できます",
          onSelect: deleteRows,
        },
      ]}
    />
  )
}