Skip to Content

DataTable

정렬, 필터링, 페이지네이션을 지원하는 고급 데이터 테이블


개요

DataTable은 TanStack Table과 @dnd-kit 기반의 고급 데이터 테이블 컴포넌트입니다. 정렬, 필터링, 페이지네이션, 행 선택, 인라인 편집 등 다양한 기능을 통합 제공합니다.

주요 특징

  • 정렬/필터링: 컬럼별 정렬 및 필터 (텍스트, 셀렉트, 범위, 날짜 등)
  • 페이지네이션: 클라이언트/서버 사이드
  • 행 선택: 단일/다중 선택
  • 인라인 편집: 셀 단위 편집
  • 컬럼 관리: 리사이즈, 리오더, 피닝, 가시성 토글
  • 행 피닝: 특정 행 상단/하단 고정
  • 서버 사이드: 수동 페이지네이션/정렬/필터링
  • 접근성: 키보드 네비게이션
  • 디자인 토큰: 테마 커스터마이징 지원

기본 테이블

이름
이메일
역할
홍길동
hong@example.com
관리자
김철수
kim@example.com
분석가
이영희
lee@example.com
뷰어
전체 건수 3

Features

행 선택

이름
이메일
역할
홍길동
hong@example.com
관리자
김철수
kim@example.com
분석가
이영희
lee@example.com
뷰어
전체 건수 3

최대 높이 (스크롤)

지표
현재 값
이전 값
변화율
페이지뷰
125,430
118,200
+6.1%
세션
45,200
42,800
+5.6%
순 방문자
32,100
30,500
+5.2%
이탈률
42.3%
44.1%
-4.1%
평균 체류시간
3m 24s
3m 10s
+7.4%
전체 건수 5

필터링 + 정렬 + 편집

컬럼 meta에 필터 옵션을 설정하고, editable로 인라인 편집을 활성화합니다. editType: "lookup"을 지정하면 검색 가능한 Combobox로 편집합니다.

Name
Category
Price
₩1,200,000
₩89,000
₩35,000
₩450,000
₩65,000
전체 건수 5

인라인 편집 타입

meta.editType으로 셀 편집 UI 타입을 지정합니다. lookup은 검색 가능한 Combobox로 렌더링됩니다.

이름 (text)
부서 (lookup)
상태 (select)
동의 (switch)
Engineering
동의
Design
미동의
Marketing
동의

필터 순서 제어 + 컬럼 선택기 숨김

meta.filterOrder로 컬럼 정의 순서와 별개로 필터 UI 표시 순서를 지정할 수 있습니다. filterOrder 값이 있는 필터가 우선 배치되고, 없는 필터는 추가된 순서를 유지합니다. showColumnSelector={false}로 컬럼 선택기를 숨길 수 있으며, Reset 버튼은 활성 필터가 있을 때만 표시됩니다.

Name
Category
Status
Price
노트북
Electronics
active
₩1,200,000
키보드
Electronics
active
₩89,000
티셔츠
Clothing
inactive
₩35,000
모니터
Electronics
active
₩450,000
후드집업
Clothing
active
₩65,000
전체 건수 5

컬럼/행 피닝

ID
이름
이메일
부서
역할
상태
1
홍길동
hong@example.com
마케팅
매니저
비활성
2
김철수
kim@example.com
개발
시니어
활성
3
이영희
lee@example.com
디자인
주니어
활성
4
박지민
park@example.com
마케팅
시니어
비활성
5
최수진
choi@example.com
개발
주니어
활성
6
정민호
jung@example.com
디자인
매니저
활성
7
강서연
kang@example.com
마케팅
주니어
비활성
8
윤태호
yoon@example.com
개발
시니어
활성
9
임지현
lim@example.com
디자인
매니저
활성
10
한승우
han@example.com
마케팅
주니어
비활성
전체 건수 10

서버 사이드 페이지네이션

<DataTable columns={columns} data={data} getRowId={(row) => row.id} manualPagination pageCount={totalPages} pageSizeOptions={[10, 20, 50]} onPaginationChange={({ pageIndex, pageSize }) => { fetchData(pageIndex, pageSize) }} />

사용 예시

예시 1: 분석 지표 테이블

지표
현재 값
이전 값
변화율
페이지뷰
125,430
118,200
+6.1%
세션
45,200
42,800
+5.6%
순 방문자
32,100
30,500
+5.2%
이탈률
42.3%
44.1%
-4.1%
평균 체류시간
3m 24s
3m 10s
+7.4%
전체 건수 5

예시 2: 커스텀 셀 렌더링

상품명
가격
상태
재고
무선 키보드
₩89,000
판매중
45
게이밍 마우스
₩65,000
판매중
8
USB-C 허브
₩42,000
품절
0
모니터 암
₩55,000
판매중
23
웹캠 HD
₩78,000
품절
3
전체 건수 5

API Reference

Props

PropTypeDefaultDescription
columnsDataTableColumnDef<T>[][]컬럼 정의
dataT[][]데이터 배열
getRowId(row: T) => string-행 고유 ID 함수 (필수)
titleReact.ReactNode-테이블 제목
actionsReact.ReactNode-액션 영역
selectablebooleanfalse행 선택 활성화
enableMultiRowSelectionbooleanfalse다중 선택 허용
enableRowSelection(row: Row) => boolean() => true행별 선택 가능 여부
editablebooleanfalse인라인 편집 활성화
manualPaginationbooleanfalse서버 사이드 페이지네이션
manualSortingbooleanfalse서버 사이드 정렬
manualFilteringbooleanfalse서버 사이드 필터링
maxHeightstring | number-최대 높이 (스크롤)
loadingbooleanfalse로딩 상태
pageCountnumber-전체 페이지 수 (서버)
rowCountnumber-전체 행 수 (서버)
pageSizeOptionsnumber[][10,20,50,100]페이지 크기 옵션
tableLayout"auto" | "fixed"-테이블 레이아웃
showColumnSelectorbooleantrue컬럼 선택기 표시 여부
enableRowPinningbooleanfalse행 피닝 활성화
onRowSelectionChange(rows: T[]) => void-행 선택 변경 핸들러
onPaginationChange(state) => void-페이지 변경 핸들러
onSortingChange(state) => void-정렬 변경 핸들러
onCellUpdate(rowIdx, colId, val) => void-셀 업데이트 핸들러
onRowClick(row: T) => void-행 클릭 핸들러
onRowDoubleClick(row: T) => void-행 더블클릭 핸들러
classNamestring-추가 CSS 클래스

DataTableColumnDef

TanStack Table의 ColumnDef를 확장합니다.

PropTypeDefaultDescription
idstring-컬럼 고유 ID (필수)
headerstring | Function-헤더 텍스트/렌더 함수
accessorKeystring-데이터 접근 키
sizenumber-컬럼 너비 (px)
cellFunction-셀 커스텀 렌더 함수
enableSearchboolean-검색 활성화
metaobject-필터/편집/피닝 설정

Column Meta

PropTypeDescription
filterVariant"text" | "select" | "range" | "switch" | "checkbox" | "date"필터 유형
filterPlaceholderstring필터 플레이스홀더
filterAlwaysShowboolean필터 항상 표시
filterOptions{ label, value }[]select 필터 옵션
filterOrdernumber필터 표시 순서 (값이 있는 필터가 우선, 오름차순)
filterFormat(value: FilterValue) => string | React.ReactNode필터 값 포맷 함수
editableboolean셀 편집 가능 여부
pinned"left" | "right"컬럼 고정 위치

기본 사용법

import { DataTable, type DataTableColumnDef } from "@vortex/ui-icignal" const columns: DataTableColumnDef<User>[] = [ { id: "name", header: "이름", accessorKey: "name", size: 150 }, { id: "email", header: "이메일", accessorKey: "email", size: 200 }, ] const data = [ { id: "1", name: "홍길동", email: "hong@example.com" }, ] <DataTable columns={columns} data={data} getRowId={(row) => row.id} />

필터/정렬/편집 통합 예시

import { DataTable, type DataTableColumnDef } from "@vortex/ui-icignal" import { useState } from "react" interface Metric { id: string name: string category: string value: number status: "active" | "inactive" } const [data, setData] = useState<Metric[]>([ { id: "1", name: "페이지뷰", category: "트래픽", value: 12500, status: "active" }, { id: "2", name: "세션", category: "트래픽", value: 3200, status: "active" }, { id: "3", name: "이탈률", category: "트래픽", value: 42, status: "inactive" }, { id: "4", name: "매출", category: "매출", value: 98000, status: "active" }, { id: "5", name: "ARPU", category: "매출", value: 1250, status: "active" }, ]) const columns: DataTableColumnDef<Metric>[] = [ { id: "name", header: "지표명", accessorKey: "name", size: 150, enableSearch: true, }, { id: "category", header: "카테고리", accessorKey: "category", size: 120, meta: { filterVariant: "select", filterOptions: [ { label: "트래픽", value: "트래픽" }, { label: "매출", value: "매출" }, ], }, }, { id: "value", header: "값", accessorKey: "value", size: 100, meta: { editable: true }, }, { id: "status", header: "상태", accessorKey: "status", size: 100, meta: { filterVariant: "select", filterOptions: [ { label: "활성", value: "active" }, { label: "비활성", value: "inactive" }, ], }, }, ] <DataTable columns={columns} data={data} getRowId={(row) => row.id} title="분석 지표" selectable editable onCellUpdate={(rowIndex, columnId, value) => { setData((prev) => prev.map((row, i) => (i === rowIndex ? { ...row, [columnId]: value } : row)) ) }} onRowSelectionChange={(rows) => console.log("선택:", rows)} />

접근성

ARIA 속성

<DataTable columns={columns} data={data} getRowId={(row) => row.id} /> // 자동: role="table", role="row", role="cell" 등

권장 사항

  • ✅ 각 컬럼에 명확한 header 텍스트 제공
  • ✅ 컬럼에 항상 idsize 명시
  • ✅ 키보드: Tab으로 셀 이동, 정렬/선택 조작
  • ✅ 로딩 상태에서 loading prop 활용
  • ❌ 과도한 컬럼 수로 가독성 저하 지양

관련 컴포넌트

Last updated on