D·Camp UI

Analytics

DataTable

Dark Mode

DataTable, TableToolbar, TablePagination을 조합하는 합성 테이블 컴포넌트. useDataTable hook의 tableProps를 스프레드하면 열 DnD, 헤더 팝오버(컬럼 설정), 행 선택(체크박스), 조건부 셀 스타일이 자동 연동됩니다.

import { DataTable } from "@/shared/ui/widget/analytics/table"

합성 컴포넌트 구조

DataTable은 단독으로 사용하지 않고, 하위 컴포넌트를 직접 조합하여 구성합니다. useDataTable hook이 모든 상태를 통합 관리하며, 각 컴포넌트에 toolbarProps, tableProps, paginationProps를 스프레드하면 자동으로 연동됩니다.

요소역할
useDataTable검색 · 필터 · 정렬 · 컬럼 가시성 · 페이지네이션 · 그룹화 · config 직렬화를 통합 관리하는 hook
useJoinedDataTable마스터 키 기준으로 여러 DataSource를 가로 병합하는 hook. 내부적으로 useDataTable을 확장
TableToolbar필터 · 검색 · 다중 정렬 · 필드 가시성 + 커스텀 액션 슬롯
DataTable컬럼 헤더 렌더링 (클릭 → 컬럼명/정렬/너비 설정 팝오버)
TableRow / TableCell행과 셀. Cell의 variant로 date · status · tag 프리셋 지원
GroupHeaderRow그룹 토글 헤더. 가로 스크롤 시 라벨 고정, 접기/펴기 지원
TablePagination페이지 이동 · 페이지 크기 선택 (그룹화 시 자동 비활성화)
기본 사용법 — useDataTable
// 1. Hook으로 상태 생성
const table = useDataTable({
  data, columns,
  pageSize: 10,
  editable: true,  // 편집 모드 활성화
});

// 2. 각 영역에 props 스프레드 — 모든 기능 자동 연동
<TableToolbar
  {...table.toolbarProps}
  onAddRow={handleAddRow}          // 행 추가 버튼
  onAddColumn={handleAddColumn}    // 열 추가 버튼
  onDeleteSelected={table.removeSelectedRows}  // 선택 삭제
  onClearSelection={table.clearSelection}
/>

<DataTable {...table.tableProps}>  {/* DnD + 체크박스 자동 */}
  {table.rows.map(row => (
    <TableRow
      key={row.id}
      selectable    // 체크박스
      selected={table.selectedIndices.has(table.getOriginalIndex(row))}
      onSelectChange={() => table.toggleSelect(table.getOriginalIndex(row))}
    >
      <TableCell editable onCellChange={...}>{row.name}</TableCell>
    </TableRow>
  ))}
</DataTable>

<TablePagination {...table.paginationProps} />

포트폴리오 테이블

Toolbar의 필터 · 검색 · 다중 정렬 · 필드 가시성과 헤더 팝오버, 페이지네이션이 모두 연동되는 전체 조합 예시입니다.

8
포트폴리오 회사
포트폴리오 회사현재 가치
회수액
MOIC
IRR
등급
섹터
Date
(주)테크스타트12억3억2.4x35%In Progress딥테크2018
(주)헬스랩4.5억1억1.5x18%Done바이오2021
(주)그린에너지8억00.8x-5%Pending클린테크2023
(주)핀테크솔루션15억5억2.9x42%Cancelled핀테크2020
(주)푸드커넥트2.5억0.5억1.3x12%In ReviewF&B2022
(주)에듀플러스6억2억2.0x28%Done에듀테크2021
(주)로보틱스AI20억02.5x38%In Progress딥테크2023
(주)클라우드넷3억1억0.7x-8%CancelledSaaS2019

TableViewConfig — 테이블 상태 직렬화

table.config는 현재 테이블의 필터 · 정렬 · 컬럼 너비 · 가시성 등을 JSON으로 직렬화한 객체입니다. DB에 저장했다가 applyConfig()로 복원하면 어디서 열어도 동일한 테이블 뷰를 재현할 수 있습니다.

config 사용법
// table.config — 현재 테이블 상태를 JSON으로 직렬화
const { config, applyConfig } = useDataTable({ ... });

// config 값 예시 (version 2)
{
  "version": 2,
  "filters": [{ "columnKey": "sector", "comparison": "contains", "value": "딥테크" }],
  "sortConfigs": [{ "key": "irr", "direction": "desc" }],
  "visibleKeys": ["company", "irr", "grade"],
  "columnOrder": ["company", "irr", "grade", "sector"],
  "columns": [{ "key": "company", "width": 200, "variant": "text" }],
  "searchKey": "company",
  "searchValue": "",
  "pageSize": 10,
  "page": 1,
  "collapsedGroups": []
}

// DB에서 불러온 설정 복원
applyConfig(savedConfig);

table.config — 현재 포트폴리오 테이블 설정 (실시간)

{
  "version": 2,
  "filters": [],
  "sortConfigs": [],
  "visibleKeys": [
    "company",
    "currentValue",
    "recovery",
    "moic",
    "irr",
    "grade",
    "sector",
    "date"
  ],
  "columnOrder": [
    "company",
    "currentValue",
    "recovery",
    "moic",
    "irr",
    "grade",
    "sector",
    "date"
  ],
  "columns": [
    {
      "key": "company",
      "label": "포트폴리오 회사",
      "width": 180
    },
    {
      "key": "currentValue",
      "label": "현재 가치",
      "width": 90
    },
    {
      "key": "recovery",
      "label": "회수액",
      "width": 80
    },
    {
      "key": "moic",
      "label": "MOIC",
      "width": 80
    },
    {
      "key": "irr",
      "label": "IRR",
      "width": 80
    },
    {
      "key": "grade",
      "label": "등급",
      "width": 110
    },
    {
      "key": "sector",
      "label": "섹터",
      "width": 120
    },
    {
      "key": "date",
      "label": "Date",
      "width": 100
    }
  ],
  "searchKey": "company",
  "searchValue": "",
  "pageSize": 10,
  "page": 1,
  "collapsedGroups": []
}

데이터 소스 병합 (Horizontal JOIN)

useJoinedDataTable hook을 사용하면 마스터 키를 기준으로 여러 데이터 소스의 컬럼을 가로로 병합할 수 있습니다. 툴바의 필드 드롭다운에서 소스별로 그룹화된 열을 개별적으로 표시/숨김 할 수 있습니다. 마스터 키 컬럼은 가로 스크롤 시에도 왼쪽에 고정됩니다.

데이터 소스 병합 — useJoinedDataTable
// 데이터 소스 정의
const sources: DataSource[] = [
  {
    id: "investment",
    label: "투자",
    color: "primary",
    columns: [
      { key: "value", label: "현재 가치", sortable: true },
      { key: "irr",   label: "IRR",       sortable: true },
    ],
    data: investmentData,
  },
  // ...다른 소스
];

// Hook 생성
const joined = useJoinedDataTable({
  masterKey: "companyName",
  masterColumn: { key: "companyName", label: "기업명", primary: true },
  sources,
});

// 툴바 — 필드 드롭다운에서 소스별 열 관리
<TableToolbar {...joined.toolbarProps} />

// 테이블 렌더링 (masterKey 컬럼은 자동 고정)
<DataTable {...joined.tableProps}>
  {joined.rows.map(row => (
    <TableRow key={String(row.companyName)}>
      {joined.visibleKeys.map(key => (
        <TableCell key={key} primary={key === "companyName"}>
          {String(row[key] ?? "")}
        </TableCell>
      ))}
    </TableRow>
  ))}
</DataTable>
행 그룹화 — groupBy
// groupBy로 행 그룹화 (그룹화 시 페이지네이션 자동 비활성화)
const joined = useJoinedDataTable({
  masterKey: "companyName",
  masterColumn: masterCol,
  sources,
  groupBy: {
    key: "building",
    label: "건물",
    resolve: { "(주)테크스타트": "A동", "(주)헬스랩": "B동", ... },
  },
});

// groups가 있으면 그룹 렌더링, 없으면 flat 렌더링
<DataTable {...joined.tableProps}>
  {joined.groups?.map(group => (
    <Fragment key={group.key}>
      <GroupHeaderRow
        label={`${joined.groupByLabel}: ${group.key}`}
        count={group.count}
        collapsed={group.collapsed}
        onToggle={() => joined.toggleGroup(group.key)}
      />
      {!group.collapsed && group.rows.map(row => (
        <TableRow key={...}>
          {/* cells */}
        </TableRow>
      ))}
    </Fragment>
  ))}
</DataTable>
8
기업명
투자멘토링PR/보도
기업명현재 가치
회수액
MOIC
IRR
멘토명
기간
멘토링 상태
보도일
매체
헤드라인
건물: A동(4건)
(주)테크스타트12억3억2.4x35%김혁신6개월완료2024-01-15한국경제AI 스타트업 성장
(주)그린에너지8억00.8x-5%박전문4개월완료2024-03-10조선비즈탄소중립 기술 특허
(주)푸드커넥트2.5억0.5억1.3x12%정식품2개월대기2024-04-01중앙일보F&B 플랫폼 론칭
(주)로보틱스AI20억02.5x38%김혁신6개월진행중2024-05-12전자신문산업용 로봇 출시
건물: B동(4건)
(주)헬스랩4.5억1억1.5x18%이성장3개월진행중2024-02-20매일경제디지털 헬스케어 확장
(주)핀테크솔루션15억5억2.9x42%최금융6개월완료2023-11-05서울경제시리즈B 투자 유치
(주)에듀플러스6억2억2.0x28%한교육5개월진행중2024-01-30동아일보에듀테크 수상
(주)클라우드넷3억1억0.7x-8%윤클라3개월중단2023-09-22디지털타임스클라우드 보안 강화

고급 기능 데모

열 순서 변경, 뷰 개인화(localStorage), 동적 열/행 추가 기능을 체험해 보세요. 툴바의 순서 버튼으로 열 순서를 변경하고, 북마크 아이콘으로 현재 설정을 저장/불러올 수 있습니다.

5
기업명
업종
매출액
직원 수
알파테크AI120억45
그린에너지에너지85억32
블루헬스헬스케어200억78
데이터플로우SaaS50억20
스마트팜농업30억15
5 (편집 모드)

table.config — 실시간 설정

{
  "version": 2,
  "filters": [],
  "sortConfigs": [],
  "visibleKeys": [
    "name",
    "industry",
    "revenue",
    "employees"
  ],
  "columnOrder": [
    "name",
    "industry",
    "revenue",
    "employees"
  ],
  "columns": [
    {
      "key": "name",
      "label": "기업명",
      "width": 140
    },
    {
      "key": "industry",
      "label": "업종",
      "width": 100
    },
    {
      "key": "revenue",
      "label": "매출액",
      "width": 100,
      "align": "right"
    },
    {
      "key": "employees",
      "label": "직원 수",
      "width": 90,
      "align": "right"
    }
  ],
  "searchKey": null,
  "searchValue": "",
  "pageSize": 10,
  "page": 1,
  "collapsedGroups": []
}

TableCell Variants

Variant미리보기설명
text (기본)일반 텍스트 내용variant 생략 시 기본값
date2024-03-15캘린더 아이콘 + 날짜 텍스트
status
DoneIn ProgressPending
컬러 dot + 상태 텍스트
tag딥테크pill 배경의 태그 형태

Props

DataTable

PropTypeRequiredDefault설명
columnsTableColumn[]컬럼 정의 목록.
childrenReactNode테이블 바디 영역. TableRow + TableCell 조합.
sortConfigsSortConfig[][]다중 정렬 설정.
onColumnUpdate(key: string, updates: ColumnUpdate) => void헤더 팝오버에서 컬럼 속성 변경 시 호출.
onColumnOrderChange(keys: string[]) => void열 DnD 시 호출. tableProps에 자동 포함.
sourceGroupsSourceGroup[]데이터 소스 그룹. 그룹 헤더 + 그룹 DnD 활성화.
selectableboolean행 선택 체크박스 표시. tableProps에 자동 포함 (editable=true 시).
allSelectedboolean전체 선택 상태. tableProps에 자동 포함.
someSelectedboolean부분 선택 상태 (indeterminate). tableProps에 자동 포함.
onToggleSelectAll() => void전체 선택 토글. tableProps에 자동 포함.
classNamestring루트 요소 추가 클래스.

TableRow

PropTypeRequiredDefault설명
childrenReactNodeTableCell 목록.
selectedboolean행 선택 하이라이트.
selectableboolean체크박스 표시 여부.
onSelectChange() => void체크박스 토글 콜백.
onClick() => void행 클릭 핸들러.
classNamestring추가 클래스.

TableCell

PropTypeRequiredDefault설명
childrenReactNode셀 콘텐츠.
variantCellVariant'text'셀 유형.
statusColorStatusColor'grey'상태/태그 계열 색상.
conditionsColumnCondition[]조건부 스타일. 셀 텍스트 매칭 시 색상/variant 오버라이드.
align'left' | 'center' | 'right''left'텍스트 정렬.
primaryboolean좌측 sticky 고정 컬럼.
editableboolean더블클릭 인라인 편집 활성화.
onCellChange(value: string) => void편집 확정 시 콜백.
classNamestring추가 클래스.