표 Table
표는 데이터를 하나 이상의 행과 열로 조직화하여 표현하는 형식으로 사용자가 빠르게 많은 양의 정보를 확인하고 비교할 수 있도록 도와준다. 기본적으로 대화형 요소가 아니기 때문에 열 제목에 데이터를 정렬하기 위한 컨트롤 요소가 포함된 상황 외에 행 전체나 데이터 셀이 대화형으로 작동하지 않는다.
기본 테이블
columns로 열을, rows로 행 데이터를 정의합니다. 각 행의 첫 번째 셀은 행 제목(th scope="row")으로 렌더되고, headerStyle의 width는 colgroup의 열 너비로도 쓰입니다. KRDS 표 스타일은 class에 data가 있을 때 적용되므로 원본 KRDS 마크업처럼 col data를 지정합니다. caption은 화면에 보이지 않고 스크린 리더로 읽히므로 표의 구성을 설명하는 문장으로 씁니다.
| 제목1 | 제목2 |
|---|---|
| 제목1-1 | 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. |
| 제목1-2 | 내용이 들어갑니다. |
| 제목1-3 | 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. |
<script setup lang="ts">
import { KrdsTable } from '@krds.ui/vue'
const columns = [
{ name: 'title', label: '제목1', field: 'title', headerStyle: 'width: 30%' },
{ name: 'content', label: '제목2', field: 'content' }
]
const rows = [
{
title: '제목1-1',
content:
'내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다.'
},
{ title: '제목1-2', content: '내용이 들어갑니다.' },
{ title: '제목1-3', content: '내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다. 내용이 들어갑니다.' }
]
</script>
<template>
<KrdsTable
caption="000에 대한 표로 제목1,제목2에 대한 내용으로 구성되어 있으며 제목1은 제목1-1,제목1-2,제목1-3으로 구성되어있다."
class="col data"
:columns="columns"
:rows="rows"
/>
</template>행 클릭
row-click 리스너가 있을 때만 행이 포커스를 받고(tabindex="0") 클릭이나 Enter·Space 키로 선택됩니다. 리스너가 없으면 행은 대화형으로 동작하지 않습니다.
| 이름 | 점수 |
|---|---|
| 김철수 | 95 |
| 이영희 | 78 |
| 박민수 | 88 |
선택된 행: 없음
<script setup lang="ts">
import { ref } from 'vue'
import { KrdsTable, type TableRow } from '@krds.ui/vue'
const columns = [
{ name: 'name', label: '이름', field: 'name' },
{ name: 'score', label: '점수', field: 'score' }
]
const rows = [
{ name: '김철수', score: 95 },
{ name: '이영희', score: 78 },
{ name: '박민수', score: 88 }
]
const selected = ref('없음')
const onRowClick = (row: TableRow, index: number) => {
selected.value = `${row.name} (${index})`
}
</script>
<template>
<KrdsTable
caption="행을 클릭하거나 Enter·Space로 선택하는 테이블"
class="col data"
:columns="columns"
:rows="rows"
@row-click="onRowClick"
/>
<p style="margin-top: 1.6rem">선택된 행: {{ selected }}</p>
</template>스타일 & 클래스 기능
열마다 헤더 셀에는 headerStyle·headerClasses를, 바디 셀에는 style·classes를 지정합니다. 바디 셀의 style·classes는 행 데이터를 받는 함수로도 줄 수 있습니다. align을 지정하면 헤더와 바디 셀에 text-<align> 클래스가 붙습니다. 클래스의 스타일은 앱의 CSS에서 정의합니다.
| ID | 이름 | 점수 | 상태 |
|---|---|---|---|
| 1 | 김철수 | 95 | PASS |
| 2 | 이영희 | 78 | FAIL |
| 3 | 박민수 | 88 | PASS |
| 4 | 정수진 | 92 | PASS |
<script setup lang="ts">
import { KrdsTable, type TableColumn, type TableRow } from '@krds.ui/vue'
const columns: TableColumn[] = [
{
name: 'id',
label: 'ID',
field: 'id',
headerStyle: 'width: 80px',
headerClasses: 'bg-gray-100 text-center font-bold',
style: 'width: 80px',
classes: 'text-center',
align: 'center'
},
{
name: 'name',
label: '이름',
field: 'name',
headerStyle: 'width: 150px; color: #333',
classes: 'font-medium'
},
{
name: 'score',
label: '점수',
field: 'score',
headerStyle: 'width: 100px',
headerClasses: 'text-right',
classes: (row: TableRow) => ((row.score as number) >= 80 ? 'score-high text-right' : 'score-low text-right'),
align: 'right'
},
{
name: 'status',
label: '상태',
field: 'status',
headerClasses: 'text-center',
classes: (row: TableRow) => `status-${(row.status as string).toLowerCase()} text-center`,
align: 'center'
}
]
const rows = [
{ id: 1, name: '김철수', score: 95, status: 'PASS' },
{ id: 2, name: '이영희', score: 78, status: 'FAIL' },
{ id: 3, name: '박민수', score: 88, status: 'PASS' },
{ id: 4, name: '정수진', score: 92, status: 'PASS' }
]
</script>
<template>
<KrdsTable caption="헤더와 바디에 스타일/클래스가 적용된 테이블" class="col data" :columns="columns" :rows="rows" />
</template>셀 슬롯
배지·버튼·체크박스처럼 글자가 아닌 내용은 열 이름(name)으로 슬롯을 받아 그립니다. #cell-<name>은 본문 셀 내용을 바꾸고 { row, column, value, index }를 받습니다(value는 field로 꺼낸 값). #header-<name>은 헤더 셀 내용을 바꿔 화면에 숨긴 열 제목 등에 씁니다. 셀 태그(첫 열은 th scope="row")와 style·classes는 그대로 유지되고, 슬롯으로만 그리는 열은 field를 생략합니다. 버튼처럼 같은 이름이 행마다 반복되면 숨김 텍스트로 어느 행의 버튼인지 알려 줍니다.
| 민원명 | 처리 상태 | 신청일 | 관리 |
|---|---|---|---|
| 주민등록표 등본 발급 | 완료 | 2026.10.02 | |
| 전입 신고 | 처리 중 | 2026.10.05 | |
| 여권 재발급 | 반려 | 2026.10.07 |
<script setup lang="ts">
import { KrdsBadge, KrdsButton, KrdsTable } from '@krds.ui/vue'
const columns = [
{ name: 'title', label: '민원명', field: 'title', headerStyle: 'width: 40%' },
{ name: 'status', label: '처리 상태', field: 'status' },
{ name: 'date', label: '신청일', field: 'date' },
// 슬롯으로만 그리는 열은 field를 생략한다
{ name: 'action', label: '관리' }
]
const rows = [
{ id: 1, title: '주민등록표 등본 발급', status: '완료', date: '2026.10.02' },
{ id: 2, title: '전입 신고', status: '처리 중', date: '2026.10.05' },
{ id: 3, title: '여권 재발급', status: '반려', date: '2026.10.07' }
]
const badgeColor = { 완료: 'success', '처리 중': 'information', 반려: 'danger' } as const
</script>
<template>
<KrdsTable caption="민원 신청 내역: 민원명, 처리 상태, 신청일, 관리로 구성" class="col data" :columns="columns" :rows="rows">
<template #cell-status="{ value }">
<KrdsBadge type="bg-light" :color="badgeColor[value as keyof typeof badgeColor]">{{ value }}</KrdsBadge>
</template>
<template #header-action><span class="sr-only">관리</span></template>
<template #cell-action="{ row }">
<KrdsButton text size="small"
>상세 보기<span class="sr-only">: {{ row.title }}</span></KrdsButton
>
</template>
</KrdsTable>
</template>빈 데이터 (기본)
rows가 비어 있으면 모든 열을 합친 셀에 "데이터가 없습니다."를 표시합니다.
| ID | 이름 | 이메일 |
|---|---|---|
| 데이터가 없습니다. | ||
<script setup lang="ts">
import { KrdsTable } from '@krds.ui/vue'
const columns = [
{ name: 'id', label: 'ID', field: 'id' },
{ name: 'name', label: '이름', field: 'name' },
{ name: 'email', label: '이메일', field: 'email' }
]
</script>
<template>
<KrdsTable caption="데이터가 없는 테이블" class="col data" :columns="columns" :rows="[]" />
</template>빈 데이터 (커스텀 슬롯)
no-data 슬롯으로 빈 상태 내용을 바꿉니다.
| ID | 이름 | 이메일 |
|---|---|---|
데이터를 찾을 수 없습니다 새로운 데이터를 추가해보세요 | ||
<script setup lang="ts">
import { KrdsTable } from '@krds.ui/vue'
const columns = [
{ name: 'id', label: 'ID', field: 'id' },
{ name: 'name', label: '이름', field: 'name' },
{ name: 'email', label: '이메일', field: 'email' }
]
</script>
<template>
<KrdsTable caption="커스텀 no-data 슬롯이 있는 테이블" class="col data" :columns="columns" :rows="[]">
<template #no-data>
<div style="padding: 2rem; text-align: center; color: #666">
<div style="font-size: 1.2rem; margin-bottom: 0.5rem">데이터를 찾을 수 없습니다</div>
<div style="font-size: 0.9rem">새로운 데이터를 추가해보세요</div>
</div>
</template>
</KrdsTable>
</template>KrdsTable
Props
| 이름 | 타입 | 기본값 | 설명 |
|---|---|---|---|
class | KrdsClassValue | - | CSS 클래스 |
caption | string | - | 테이블 캡션 |
columns (필수) | TableColumn[] | - | 테이블 열 정의 |
rows (필수) | TableRow[] | - | 테이블 행 데이터 |
Events
| 이름 | 인자 | 설명 |
|---|---|---|
row-click | [row: TableRow, index: number] | 행을 클릭했을 때 (행, 순서) |
Slots
| 이름 | 설명 |
|---|---|
no-data | 행이 없을 때 표시할 내용 |
열 이름 슬롯
열 이름(name)마다 받는 슬롯입니다. 이름이 열 정의에 따라 정해져 위 Slots 표에는 나오지 않습니다.
| 이름 | 인자 | 설명 |
|---|---|---|
cell-<name> | { row: TableRow, column: TableColumn, value: unknown, index: number } | 본문 셀 내용. 셀 태그와 style·classes는 유지 |
header-<name> | { column: TableColumn } | 헤더 셀 내용 (예: 화면에 숨긴 열 제목) |