Appearance
데이터 테이블 (Data Table)
DataTable 컴포넌트는 Headless UI 라이브러리 TanStack Table을 기반으로 구축된 테이블 컴포넌트입니다.
display: grid와 grid-template-columns를 사용하여 컬럼 리사이징이 가능하도록 구현되었습니다. 한 줄의 설정으로 헤더와 바디의 컬럼의 크기가 동일하게 적용됩니다. 이전보다 컬럼의 크기를 조절하는 성능이 개선 되었습니다.
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
최민수
minsu.choi@example.com
매니저
기획팀
활성
2024-01-05 16:45
정수민
sumin.jung@example.com
사용자
개발팀
차단
2023-12-25 10:00
주요 기능 (Features)
- 행 선택 (Row Selection): 단일 및 다중 행 선택을 지원합니다.
- 정렬 (Sorting): UI 인디케이터를 포함한 단일 컬럼 정렬 (오름차순/내림차순)을 지원합니다.
- 컬럼 리사이징 (Column Resizing): 전체 높이 시각적 가이드(Full-height visual guide)를 제공하는 인터랙티브 컬럼 리사이징을 지원합니다.
- 컬럼 표시 제어 (Column Visibility): 프로그래밍 방식으로 컬럼의 표시 여부를 제어할 수 있습니다.
- 커스텀 셀 (Custom Cells): Vue 컴포넌트 또는 렌더 함수(Render functions)를 사용하여 셀 렌더링을 완전히 커스터마이징할 수 있습니다.
- 로딩 및 빈 상태 (Loading & Empty States): 로딩 중이거나 데이터가 없을 때를 처리하기 위한 전용 Slot과 Prop을 제공합니다.
- 툴팁 지원 (Tooltip Support): 내용이 길어 잘리는 경우(Ellipsis), 툴팁을 통해 전체 내용을 확인할 수 있습니다.
- 다양한 크기 (Sizes):
small,normal(기본),large세 가지 크기를 지원합니다.
테이블 변형 (Table Variant)
variant prop을 사용하여 테이블의 시각적 스타일을 inset (기본값) 또는 attached 모드로 설정할 수 있습니다.
Inset (Default)
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
Attached
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
테이블 크기 (Table Size)
size prop을 사용하여 테이블 행의 높이와 폰트 크기를 조절할 수 있습니다.
Small
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
Normal (Default)
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
Large
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
그리드 라인 (Grid Lines)
show-grid-lines prop을 사용하여 데이터 셀의 세로 구분선을 표시할 수 있습니다.
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
최민수
minsu.choi@example.com
매니저
기획팀
활성
2024-01-05 16:45
정수민
sumin.jung@example.com
사용자
개발팀
차단
2023-12-25 10:00
스트라이프 행 (Striped Rows)
striped-rows prop을 사용하여 홀수 행에 배경색을 적용하여 가독성을 높일 수 있습니다.
이름
이메일
권한
부서
상태
마지막 접속
김철수
chulsu.kim@example.com
관리자
개발팀
활성
2024-01-15 09:30
이영희
younghee.lee@example.com
사용자
디자인팀
휴식
2024-01-20 14:20
박지성
jisung.park@example.com
사용자
마케팅팀
활성
2024-01-10 11:15
최민수
minsu.choi@example.com
매니저
기획팀
활성
2024-01-05 16:45
정수민
sumin.jung@example.com
사용자
개발팀
차단
2023-12-25 10:00
사용법 (Usage)
vue
<script setup lang="ts">
import { ref } from 'vue';
import { DataTable } from '@jennifersoft/vue-components-v2';
import type { ColumnDef } from '@tanstack/vue-table';
interface User {
id: number;
name: string;
email: string;
role: string;
department: string;
status: string;
lastLogin: string;
}
const data = ref<User[]>([
{
id: 1,
name: '김철수',
email: 'chulsu.kim@example.com',
role: '관리자',
department: '개발팀',
status: '활성',
lastLogin: '2024-01-15',
},
{
id: 2,
name: '이영희',
email: 'younghee.lee@example.com',
role: '사용자',
department: '디자인팀',
status: '휴식',
lastLogin: '2024-01-20',
},
// ... 더 많은 데이터
]);
const columns: ColumnDef<User>[] = [
{ accessorKey: 'name', header: '이름', size: 100 },
{ accessorKey: 'email', header: '이메일', size: 100 },
{ accessorKey: 'role', header: '권한', size: 100 },
{ accessorKey: 'department', header: '부서', size: 100 },
{ accessorKey: 'status', header: '상태', size: 100 },
{ accessorKey: 'lastLogin', header: '마지막 접속', size: 100 },
];
</script>
<template>
<DataTable :data="data" :columns="columns" :enable-row-selection="true" />
</template>Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | T[] | Required | 표시할 데이터 객체들의 배열입니다. |
columns | ColumnDef<T>[] | Required | 컬럼 정의 설정입니다. |
enableRowSelection | boolean | false | 행 선택을 위한 체크박스 제공 여부를 결정합니다. |
columnVisibility | VisibilityState | {} | 컬럼의 표시 상태를 정의하는 객체입니다. |
loading | boolean | false | true일 때 로딩 스켈레톤(Skeleton) 상태를 표시합니다. |
emptyText | string | 'No Data' | 데이터 배열이 비어있을 때 표시할 텍스트입니다. |
size | 'small' | 'normal' | 'large' | 'normal' | 테이블의 크기(행 높이 및 폰트)를 설정합니다. |
showGridLines | boolean | false | true일 때 데이터 셀의 세로 구분선을 표시합니다. |
stripedRows | boolean | false | true일 때 홀수 행에 배경색을 적용합니다. |
variant | 'inset' | 'attached' | 'inset' | 테이블의 시각적 스타일을 설정합니다. |
Events
| Event | Payload | Description |
|---|---|---|
update:rowSelection | RowSelectionState | 행 선택 상태가 변경될 때 발생합니다. |
update:columnVisibility | VisibilityState | 컬럼 표시 상태가 변경될 때 발생합니다. |
Slots
| Slot Name | Description |
|---|---|
loading-state | 로딩 오버레이 영역에 표시할 커스텀 콘텐츠입니다. |
empty-state | 데이터가 없을 때 표시할 커스텀 콘텐츠입니다. |
컬럼 정의 (Column Definitions)
컬럼은 @tanstack/vue-table의 ColumnDef 타입을 사용하여 정의합니다.
타입 안전한 컬럼 정의 (Type-Safe Column Definition)
createColumnHelper를 사용하면 위에서 커스텀한 meta 속성(align)의 타입 추론 및 자동 완성 지원을 받을 수 있습니다.
typescript
import { createColumnHelper } from '@tanstack/vue-table';
const columnHelper = createColumnHelper<User>();
const columns = [
columnHelper.accessor('name', {
header: '이름',
meta: {
align: 'center', // 'left' | 'center' | 'right' 자동 완성 지원
},
}),
];기본 컬럼 (Basic Column)
typescript
{
accessorKey: 'status',
header: '상태',
size: 120, // 픽셀 단위 초기 크기
minSize: 80, // 최소 크기
maxSize: 200, // 최대 크기
meta: {
align: 'center' // 'left' | 'center' | 'right' (기본값: 'left')
}
}텍스트 정렬 (Text Alignment)
컬럼 정의의 meta.align 속성을 사용하여 헤더와 셀의 텍스트 정렬을 제어할 수 있습니다.
- left: 왼쪽 정렬 (기본값)
- center: 가운데 정렬
- right: 오른쪽 정렬
이름 (Left)
권한 (Center)
금액 (Right)
Items A
Admin
1,000,000
Items B
User
500,000
Items C
Guest
10,000
vue
<script setup lang="ts">
import { DataTable } from '@jennifersoft/vue-components-v2';
import { ref } from 'vue';
const columnsWithAlignment = [
{
accessorKey: 'name',
header: '이름 (Left)',
size: 100,
meta: { align: 'left' },
},
{
accessorKey: 'role',
header: '권한 (Center)',
size: 100,
meta: { align: 'center' },
},
{
accessorKey: 'price',
header: '금액 (Right)',
size: 100,
meta: { align: 'right' },
},
];
const dataWithAlignment = ref([
{ id: 1, name: 'Items A', role: 'Admin', price: '1,000,000' },
{ id: 2, name: 'Items B', role: 'User', price: '500,000' },
{ id: 3, name: 'Items C', role: 'Guest', price: '10,000' },
]);
</script>
<template>
<DataTable
:data="dataWithAlignment"
:columns="columnsWithAlignment"
:enable-row-selection="true"
/>
</template>커스텀 셀 렌더링 (Custom Cell Rendering)
cell 속성을 사용하여 커스텀 콘텐츠나 컴포넌트를 렌더링할 수 있습니다.
typescript
{
accessorKey: 'progress',
header: '진행률',
cell: ({ getValue }) => {
// 예시: 진행률 바 렌더링
return h('div', { class: 'progress-bar' }, getValue())
}
}스타일링 (Styling)
이 컴포넌트는 유연성을 확보하고 리사이즈 핸들의 정확한 정렬을 보장하기 위해 native <table> 요소 대신 div 기반의 구조와 CSS Grid 레이아웃을 사용합니다.
- CSS Grid & Variables: 성능 최적화를 위해 CSS Grid를 사용하며,
--grid-template-columnsCSS 변수를 통해 컬럼 너비를 효율적으로 관리합니다. - 클래스 명명 (Class naming): BEM 컨벤션을 따릅니다 (예:
js-data-table,js-data-table__header). - 리사이징 (Resizing): 리사이즈 핸들은 테이블 전체 높이(헤더 + 바디)에 걸쳐 표시되도록
absolute positioning을 사용하여 구현되었습니다.
컬럼 리사이징 동작 (Column Resizing Behavior)
이 테이블은 전체 너비가 고정된 상태에서 컬럼의 비율을 조정하는 방식을 사용합니다. 사용자가 컬럼의 리사이즈 핸들을 드래그하면 다음과 같이 동작합니다:
- 그룹 분할: 리사이즈 핸들을 기준으로 좌측 그룹(핸들이 속한 컬럼 포함)과 우측 그룹으로 나뉩니다.
- 비율 유지: 핸들을 이동하여 변경된 너비만큼, 각 그룹 내의 컬럼들이 현재 비율을 유지하며 동시에 늘어나거나 줄어듭니다.
- 전체 너비 고정: 테이블 전체의 너비는 변하지 않으십니다.
예를 들어, 3개의 컬럼 A | B | C가 있을 때 B의 오른쪽 핸들을 우측으로 드래그하면:
- 좌측 그룹 (A, B): 너비가 증가하며, A와 B가 기존 비율대로 커집니다.
- 우측 그룹 (C): 너비가 감소하며, C가 작아집니다.
이 방식은 반응형 레이아웃에서 컬럼 간의 상대적인 크기 균형을 유지하는 데 유리합니다.