DataTable
정렬, 필터링, 페이지네이션을 지원하는 고급 데이터 테이블
개요
DataTable은 TanStack Table과 @dnd-kit 기반의 고급 데이터 테이블 컴포넌트입니다. 정렬, 필터링, 페이지네이션, 행 선택, 인라인 편집 등 다양한 기능을 통합 제공합니다.
주요 특징
- ✅ 정렬/필터링: 컬럼별 정렬 및 필터 (텍스트, 셀렉트, 범위, 날짜 등)
- ✅ 페이지네이션: 클라이언트/서버 사이드
- ✅ 행 선택: 단일/다중 선택
- ✅ 인라인 편집: 셀 단위 편집
- ✅ 컬럼 관리: 리사이즈, 리오더, 피닝, 가시성 토글
- ✅ 행 피닝: 특정 행 상단/하단 고정
- ✅ 서버 사이드: 수동 페이지네이션/정렬/필터링
- ✅ 접근성: 키보드 네비게이션
- ✅ 디자인 토큰: 테마 커스터마이징 지원
기본 테이블
Preview
전체 건수 3
Features
행 선택
Preview
전체 건수 3
최대 높이 (스크롤)
Preview
전체 건수 5
필터링 + 정렬 + 편집
컬럼 meta에 필터 옵션을 설정하고, editable로 인라인 편집을 활성화합니다.
Code
const columns: DataTableColumnDef<Product>[] = [
{
id: "name",
header: "Name",
accessorKey: "name",
size: 180,
meta: {
filterVariant: "text",
filterPlaceholder: "이름 검색...",
filterAlwaysShow: true,
},
},
{
id: "category",
header: "Category",
accessorKey: "category",
size: 130,
meta: {
filterVariant: "select",
filterPlaceholder: "카테고리",
filterAlwaysShow: true,
filterOptions: [
{ label: "Electronics", value: "Electronics" },
{ label: "Clothing", value: "Clothing" },
],
},
},
{
id: "price",
header: "Price",
accessorKey: "price",
size: 100,
cell: ({ getValue }) => `$${(getValue() as number).toFixed(2)}`,
meta: { editable: false },
},
]
<DataTable
columns={columns}
data={data}
getRowId={(row) => row.id}
editable
columnFilters={columnFilters}
onColumnFiltersChange={setColumnFilters}
onCellUpdate={(rowIndex, columnId, value) =>
console.log({ rowIndex, columnId, value })
}
/>필터 순서 제어 + 컬럼 선택기 숨김
meta.filterOrder로 컬럼 정의 순서와 별개로 필터 UI 표시 순서를 지정할 수 있습니다.
filterOrder 값이 있는 필터가 우선 배치되고, 없는 필터는 추가된 순서를 유지합니다.
showColumnSelector={false}로 컬럼 선택기를 숨길 수 있으며, Reset 버튼은 활성 필터가 있을 때만 표시됩니다.
Code
const columns: DataTableColumnDef<Product>[] = [
{
id: "name",
header: "Name",
accessorKey: "name",
meta: {
filterVariant: "text",
filterAlwaysShow: true,
filterOrder: 2, // 세 번째로 표시
},
},
{
id: "category",
header: "Category",
accessorKey: "category",
meta: {
filterVariant: "select",
filterAlwaysShow: true,
filterOrder: 0, // 첫 번째로 표시
filterOptions: [
{ label: "Electronics", value: "Electronics" },
{ label: "Clothing", value: "Clothing" },
],
},
},
{
id: "status",
header: "Status",
accessorKey: "status",
meta: {
filterVariant: "select",
filterAlwaysShow: true,
filterOrder: 1, // 두 번째로 표시
filterOptions: [
{ label: "Active", value: "active" },
{ label: "Inactive", value: "inactive" },
],
},
},
]
// 필터 순서: Category → Status → Name (컬럼 순서와 무관)
// 컬럼 선택기 숨김, Reset 버튼은 필터가 있을 때만 노출
<DataTable
columns={columns}
data={data}
getRowId={(row) => row.id}
columnFilters={columnFilters}
onColumnFiltersChange={setColumnFilters}
showColumnSelector={false}
/>컬럼/행 피닝
Code
const columns: DataTableColumnDef<Product>[] = [
{
id: "id",
header: "ID",
accessorKey: "id",
size: 80,
meta: { pinned: "left" },
},
{ id: "name", header: "Name", accessorKey: "name", size: 200 },
{
id: "actions",
header: "Actions",
size: 100,
meta: { pinned: "right" },
cell: () => <Button variant="ghost" size="sm">Detail</Button>,
},
]
<DataTable
columns={columns}
data={data}
getRowId={(row) => row.id}
enableRowPinning
rowPinning={{ top: ["1", "2"], bottom: ["50"] }}
maxHeight="300px"
tableLayout="fixed"
/>서버 사이드 페이지네이션
Code
<DataTable
columns={columns}
data={data}
getRowId={(row) => row.id}
manualPagination
pageCount={totalPages}
pageSizeOptions={[10, 20, 50]}
onPaginationChange={({ pageIndex, pageSize }) => {
fetchData(pageIndex, pageSize)
}}
/>사용 예시
예시 1: 분석 지표 테이블
Preview
전체 건수 5
예시 2: 커스텀 셀 렌더링
Code
import { DataTable, Badge, type DataTableColumnDef } from "@vortex/ui-icignal"
const columns: DataTableColumnDef<Product>[] = [
{ id: "name", header: "Name", accessorKey: "name", size: 150 },
{
id: "price",
header: "Price",
accessorKey: "price",
size: 100,
cell: ({ getValue }) => `$${(getValue() as number).toFixed(2)}`,
},
{
id: "status",
header: "Status",
accessorKey: "status",
size: 100,
cell: ({ getValue }) => {
const status = getValue() as string
return (
<Badge variant={status === "active" ? "default" : "secondary"}>
{status}
</Badge>
)
},
},
]API Reference
Props
| Prop | Type | Default | Description |
|---|---|---|---|
columns | DataTableColumnDef<T>[] | [] | 컬럼 정의 |
data | T[] | [] | 데이터 배열 |
getRowId | (row: T) => string | - | 행 고유 ID 함수 (필수) |
title | React.ReactNode | - | 테이블 제목 |
actions | React.ReactNode | - | 액션 영역 |
selectable | boolean | false | 행 선택 활성화 |
enableMultiRowSelection | boolean | false | 다중 선택 허용 |
enableRowSelection | (row: Row) => boolean | () => true | 행별 선택 가능 여부 |
editable | boolean | false | 인라인 편집 활성화 |
manualPagination | boolean | false | 서버 사이드 페이지네이션 |
manualSorting | boolean | false | 서버 사이드 정렬 |
manualFiltering | boolean | false | 서버 사이드 필터링 |
maxHeight | string | number | - | 최대 높이 (스크롤) |
loading | boolean | false | 로딩 상태 |
pageCount | number | - | 전체 페이지 수 (서버) |
rowCount | number | - | 전체 행 수 (서버) |
pageSizeOptions | number[] | [10,20,50,100] | 페이지 크기 옵션 |
tableLayout | "auto" | "fixed" | - | 테이블 레이아웃 |
showColumnSelector | boolean | true | 컬럼 선택기 표시 여부 |
enableRowPinning | boolean | false | 행 피닝 활성화 |
onRowSelectionChange | (rows: T[]) => void | - | 행 선택 변경 핸들러 |
onPaginationChange | (state) => void | - | 페이지 변경 핸들러 |
onSortingChange | (state) => void | - | 정렬 변경 핸들러 |
onCellUpdate | (rowIdx, colId, val) => void | - | 셀 업데이트 핸들러 |
onRowClick | (row: T) => void | - | 행 클릭 핸들러 |
onRowDoubleClick | (row: T) => void | - | 행 더블클릭 핸들러 |
className | string | - | 추가 CSS 클래스 |
DataTableColumnDef
TanStack Table의 ColumnDef를 확장합니다.
| Prop | Type | Default | Description |
|---|---|---|---|
id | string | - | 컬럼 고유 ID (필수) |
header | string | Function | - | 헤더 텍스트/렌더 함수 |
accessorKey | string | - | 데이터 접근 키 |
size | number | - | 컬럼 너비 (px) |
cell | Function | - | 셀 커스텀 렌더 함수 |
enableSearch | boolean | - | 검색 활성화 |
meta | object | - | 필터/편집/피닝 설정 |
Column Meta
| Prop | Type | Description |
|---|---|---|
filterVariant | "text" | "select" | "range" | "switch" | "checkbox" | "date" | 필터 유형 |
filterPlaceholder | string | 필터 플레이스홀더 |
filterAlwaysShow | boolean | 필터 항상 표시 |
filterOptions | { label, value }[] | select 필터 옵션 |
filterOrder | number | 필터 표시 순서 (값이 있는 필터가 우선, 오름차순) |
filterFormat | (value: FilterValue) => string | React.ReactNode | 필터 값 포맷 함수 |
editable | boolean | 셀 편집 가능 여부 |
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} />접근성
ARIA 속성
<DataTable columns={columns} data={data} getRowId={(row) => row.id} />
// 자동: role="table", role="row", role="cell" 등권장 사항
- ✅ 각 컬럼에 명확한
header텍스트 제공 - ✅ 컬럼에 항상
id와size명시 - ✅ 키보드: Tab으로 셀 이동, 정렬/선택 조작
- ✅ 로딩 상태에서
loadingprop 활용 - ❌ 과도한 컬럼 수로 가독성 저하 지양
관련 컴포넌트
Last updated on