Table
컬럼 정의 기반 정적 데이터 테이블 — 빈 상태 내장, 정렬·페이지네이션은 소비자 책임(YAGNI)입니다.
마지막 업데이트 2026-06-11
한눈에#
컬럼 정의 + 데이터 + rowKey만으로 가볍게 렌더하는 읽기 전용 정적 테이블입니다 — 빈 상태가 내장돼 있고, 정렬·페이징은 소비자 책임(YAGNI)입니다.
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
- 컬럼 정의 기반 정적 표
- 빈 상태 내장
- 정렬·페이징은 소비자
- 시맨틱 table
좁은 화면은 가로 스크롤 래퍼가 표 구조를 깨지 않고 보호 — 인터랙션이 필요하면 DataGrid
사용 시점#
읽기 전용으로 데이터를 정적으로 표시하면 Table — 정렬·선택·편집·페이징 중 하나라도 필요하면 DataGrid입니다.
권장 — 이렇게 쓰세요
지양 — 이러지 마세요
| 에이전트 | 작업 |
|---|---|
| 플래너 | 12 |
| 코더 | 34 |
쓴다 — 정렬·선택·편집·페이징이 필요 없는 읽기 전용 표(가벼운 마크업·작은 번들)
대신 DataGrid — 인라인 편집·헤더 정렬·행 선택·페이징 중 하나라도 필요할 때
플레이그라운드#
컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.
Table를 직접 조작해 보세요
속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.
플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.
해부#
셀(td)의 패딩이 표의 측정 단위입니다 — 1열 표본 위에 실측을 핀으로 얹습니다.
| 에이전트 |
|---|
| 플래너 |
- padding-block
- 12px
space-3 - padding-inline
- 16px
space-4 - font
- 14px
body-2 - border-bottom
- 1px
color.border
변형 — 커스텀 셀#
render로 셀 내용을 자유 구성합니다 — 기본 렌더는 row[key]의 문자/숫자만 표시합니다.
| 에이전트 | 상태 |
|---|---|
| 플래너 | 실행 중 |
| 리뷰어 | 대기 |
스타일 변형#
표시 의도에 맞춰 직교 변형을 조합합니다 — 기본값(divider="rows" · density="comfortable")은 위 예시 그대로이며, 옵션을 더하지 않으면 모양이 바뀌지 않습니다.
테두리 — divider#
grid는 전 셀 보더로 셀 단위 비교를 돕고(숫자 밀집·스프레드시트형), none은 헤더 띠로만 구분하는 보더리스입니다(이미 경계가 있는 카드 내부 등).
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
밀도 — density#
compact는 패딩을 space.2×space.3으로 줄여 한 화면에 더 많은 행을 — 표에 상주하는 파워유저·고밀도 데이터에 적합합니다.
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
줄무늬 — striped#
짝수 행에 중립 배경을 넣어 넓고 긴 표의 행 추적을 돕습니다. 줄무늬가 구분 역할을 하므로 divider="grid"와 함께 쓰지 않습니다(줄무늬 OR 보더).
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
| 문서봇 | 문서화 | 9 |
헤더 고정 — stickyHeader#
maxHeight로 세로 스크롤 영역을 만들면 헤더가 상단에 핀으로 고정됩니다 — 긴 표를 스크롤하며 컬럼 의미를 잃지 않습니다.
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
| 문서봇 | 문서화 | 9 |
| 테스터 | 검증 | 18 |
| 배포봇 | 릴리스 | 5 |
| 감시봇 | 모니터링 | 27 |
변형은 직교합니다 — 의도에 맞게 조합하되, 아래 가이드를 따릅니다.
| 변형 | 언제 | 주의 |
|---|---|---|
divider="rows"(기본) | 대부분의 표 — 노이즈 최소 | — |
divider="grid" | 숫자 밀집·스프레드시트형 비교 | 비숫자 표엔 과함(템플릿 인상) |
divider="none" | 카드 내부 등 이미 경계가 있는 맥락 | 단독(캔버스 위) 사용 시 표 경계가 모호 |
density="compact" | 파워유저·고밀도 데이터 | 셀 안 링크·버튼은 타깃 크기(24×24) 확보 |
striped | 넓고 긴 스캔형 행 | grid와 동시 금지 · 줄무늬·민무늬 행 모두 텍스트 대비 4.5:1 |
stickyHeader | 긴 표 스크롤 | maxHeight로 스크롤 영역 필요 |
반응형#
좁은 화면에서 가로 스크롤은 사용자를 가로·세로 양방향으로 헤매게 합니다. 표의 의도에 맞춰 전략을 고릅니다 — 기본값은 scroll(현행 가로 스크롤)이라 기존 표는 손대지 않으면 그대로입니다.
| 전략 | 언제 | 좁은 폭 동작 |
|---|---|---|
scroll(기본) | 단순한 표 | 가로 스크롤 래퍼 |
cards | 레코드형(행=한 건, 값 자체가 중요) | 행→카드 스택(라벨↔값) |
columns | 비교형(컬럼 간 값을 나란히 비교) | 우선순위 낮은 컬럼 숨김 + 행 펼치기 |
카드 스택 — cards (레코드형)#
컨테이너 폭이 좁아지면(600px 미만) 각 행을 카드로 스택해 세로 스크롤만으로 읽히는 레코드 리스트로 전환합니다. 뷰포트가 아닌 컨테이너 폭에 반응하므로(CSS Container Query) 사이드바·split·모달 안에 놓여도 올바르게 전환됩니다. 아래 두 표는 같은 컴포넌트·같은 props이고 컨테이너 폭만 다릅니다.
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
| 에이전트 | 역할 | 작업 수 |
|---|---|---|
| 플래너 | 작업 분해 | 12 |
| 코더 | 구현 | 34 |
| 리뷰어 | 코드 리뷰 | 21 |
primaryColumn으로 한 컬럼을 카드 제목으로 승격합니다(라벨 없이 강조 — 보통 행을 식별하는 이름 컬럼).- 나머지 셀은
header를 라벨로 재사용합니다.header가 아이콘 등 복합 노드면 컬럼에cardLabel로 짧은 텍스트 라벨을 따로 줍니다. - 전환 임계값은 컨테이너 폭
600px로 고정입니다(ADR-012 compact). 가변 임계값은 후속 단계에서 제공합니다.
컬럼 우선순위 — columns (비교형)#
컬럼 간 값을 나란히 비교하는 표는 카드화하면 비교가 깨집니다. responsive="columns"는 폭이 부족하면 priority가 낮은 컬럼부터 숨기고(첫 컬럼=식별자는 항상 유지) 숨긴 값은 행 펼치기로 상세에 노출합니다. 표 구조(컬럼 정렬·비교)를 보존하면서 좁은 화면에 맞춥니다. ResizeObserver로 컨테이너 폭을 측정하는 클라이언트 컴포넌트입니다.
| 에이전트 | 역할 | 작업 수 | 상태 |
|---|---|---|---|
| 플래너 | 작업 분해 | 12 | 실행 중 |
| 코더 | 구현 | 34 | 대기 |
| 리뷰어 | 코드 리뷰 | 21 | 완료 |
priority는 높을수록 더 오래 유지됩니다(기본 0). 좁아질수록 낮은 우선순위 컬럼부터 숨고, 동률이면 왼쪽 컬럼이 남습니다.- 숨긴 값은 행 끝의
+버튼(펼치기)으로 상세에 라벨↔값으로 노출됩니다. - 첫 컬럼은 행 식별자라 항상 보이며, 가로 스크롤이 생기면 sticky로 고정됩니다.
크기#
폭은 부모 100%, 좁은 화면에서는 래퍼가 가로 스크롤로 보호합니다.
셀 패딩은 기본 space.3×space.4(comfortable) — density="compact"는 space.2×space.3입니다.
상태#
| 에이전트 | 작업 수 |
|---|---|
| 아직 실행된 에이전트가 없습니다 | |
행 hover는 surface-hover 배경 — 의사클래스로 처리됩니다.
Props#
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
columns | readonly TableColumn<T>[] | — | 컬럼 정의 배열 (아래 표) |
data | readonly T[] | — | 행 데이터 — 비어 있으면 emptyContent 표시 |
rowKey | (row: T, index: number) => string | — | 행 고유 키 — index 기반 키는 재정렬 시 위험해 명시를 강제한다 |
caption | ReactNode | — | 표 이름(접근성) — 제공 시 스크롤 래퍼도 키보드 region이 된다 |
emptyContent | ReactNode | 데이터가 없습니다 | 데이터 0건일 때 표시할 내용 |
divider | 'rows' | 'grid' | 'none' | rows | 테두리/구분선 스타일 — 기본 rows(가로 구분선만). grid·none 변형 제공 |
density | 'comfortable' | 'compact' | comfortable | 밀도 — 기본 comfortable. compact는 패딩을 줄인 고밀도 |
striped | boolean | false | 줄무늬(zebra) — 짝수 행에 중립 배경. 넓고 긴 스캔형 표에 권장. divider="grid"와 동시 사용은 권장하지 않는다(줄무늬 OR 보더 — 중복 방지). |
stickyHeader | boolean | false | 헤더 고정 — 세로 스크롤 시 헤더를 상단에 핀. 동작하려면 세로 스크롤 영역이 필요하다 → maxHeight로 활성화. |
maxHeight | string | — | 세로 스크롤 영역 높이(CSS 값) — 초과 시 본문 스크롤. stickyHeader의 전제 |
responsive | 'scroll' | 'cards' | 'columns' | scroll | 반응형 전략 — 기본 scroll(현행 가로 스크롤). cards는 좁은 컨테이너(<600px)에서 행→카드 스택. |
primaryColumn | string | — | responsive="cards"에서 카드 제목으로 승격할 컬럼 key — 해당 셀은 라벨 없이 강조 렌더. 보통 행을 식별하는 컬럼(이름 등)을 지정한다. |
ref | Ref<HTMLDivElement> | — | 최외곽 스크롤 래퍼 <div>로 전달되는 ref (React 19 ref-as-prop) |
TableColumn<T>:
| Prop | 타입 | 기본값 | 설명 |
|---|---|---|---|
key | string | — | 데이터 키 또는 고유 컬럼 id — render 미지정 시 row[key] 원시값을 표시 |
header | ReactNode | — | 헤더 셀 내용 |
align | TableAlign | — | 정렬 — 숫자는 right 권장 (기본 left) |
width | string | — | 컬럼 폭 (CSS 값) |
render | (row: T, rowIndex: number) => ReactNode | — | 커스텀 셀 렌더 |
cardLabel | ReactNode | — | responsive="cards"/columns 모드에서 셀 앞·상세에 붙는 라벨 — 미지정 시 header를 재사용. header가 아이콘 등 복합 노드일 때 짧은 텍스트 라벨을 따로 줄 용도. |
priority | number | — | responsive="columns" 우선순위 — 높을수록 좁은 폭에서 더 오래 유지(기본 0). 첫 컬럼은 우선순위와 무관하게 항상 보인다(행 식별자). 동률이면 왼쪽 컬럼이 유지된다. |
접근성#
- 시맨틱
<table>렌더 —<th scope="col">헤더,caption이 표 이름 - 좁은 화면 가로 스크롤 래퍼 — 표 구조를 깨지 않고 유지
- 정렬/선택 같은 인터랙션을 더할 때는
aria-sort·행 선택 ARIA를 소비자가 함께 설계 striped는 줄무늬·민무늬 행 모두에서 텍스트 대비 ≥4.5:1을 유지(WDS 토큰 검증: 라이트 7.1:1·다크 8.2:1) — 색은 행 구분의 보조 신호이며 표 구조가 정본density="compact"에서 셀에 링크·버튼을 넣을 때는 각 컨트롤이 타깃 크기(24×24px, WCAG 2.5.8)를 충족하도록 별도 패딩/높이를 부여
토큰#
component 토큰 없이 semantic을 직접 소비합니다(신설 기준 §4 미충족).
| 속성 | 토큰 |
|---|---|
| 헤더 배경/글자 | color.surface-muted · color.text-muted |
| 구분선 | color.border (헤더 하단은 border-strong) |
| 행 hover | color.surface-hover |
| 셀 패딩 | space.3 × space.4 |