ComponentsP3 본문

Table

컬럼 정의 기반 정적 데이터 테이블 — 빈 상태 내장, 정렬·페이지네이션은 소비자 책임(YAGNI)입니다.

마지막 업데이트 2026-06-11

한눈에#

컬럼 정의 + 데이터 + rowKey만으로 가볍게 렌더하는 읽기 전용 정적 테이블입니다 — 빈 상태가 내장돼 있고, 정렬·페이징은 소비자 책임(YAGNI)입니다.

에이전트 실행 현황
에이전트역할작업 수
플래너작업 분해12
코더구현34
리뷰어코드 리뷰21
  • 컬럼 정의 기반 정적 표
  • 빈 상태 내장
  • 정렬·페이징은 소비자
  • 시맨틱 table

좁은 화면은 가로 스크롤 래퍼가 표 구조를 깨지 않고 보호 — 인터랙션이 필요하면 DataGrid

사용 시점#

읽기 전용으로 데이터를 정적으로 표시하면 Table — 정렬·선택·편집·페이징 중 하나라도 필요하면 DataGrid입니다.

권장 — 이렇게 쓰세요

지양 — 이러지 마세요

작업 현황
에이전트작업
플래너12
코더34

쓴다정렬·선택·편집·페이징이 필요 없는 읽기 전용 표(가벼운 마크업·작은 번들)

대신 DataGrid인라인 편집·헤더 정렬·행 선택·페이징 중 하나라도 필요할 때

플레이그라운드#

컨트롤로 props를 조작하면 미리보기와 코드가 실시간 갱신됩니다.

Table를 직접 조작해 보세요

속성·테마·토큰을 바꾸고 React·Flutter 코드를 확인하는 풀스크린 빌더로 엽니다.

빌더 열기

플레이그라운드는 넓은 작업 영역이 필요해 웹·태블릿에서 편집할 수 있어요.

해부#

셀(td)의 패딩이 표의 측정 단위입니다 — 1열 표본 위에 실측을 핀으로 얹습니다.

셀(td) — space.3 × space.4 단일 밀도
에이전트
플래너
padding-block
12pxspace-3
padding-inline
16pxspace-4
font
14pxbody-2
border-bottom
1pxcolor.border

변형 — 커스텀 셀#

render로 셀 내용을 자유 구성합니다 — 기본 렌더는 row[key]의 문자/숫자만 표시합니다.

에이전트상태
플래너실행 중
리뷰어대기
render — 상태 강조

스타일 변형#

표시 의도에 맞춰 직교 변형을 조합합니다 — 기본값(divider="rows" · density="comfortable")은 위 예시 그대로이며, 옵션을 더하지 않으면 모양이 바뀌지 않습니다.

테두리 — divider#

grid는 전 셀 보더로 셀 단위 비교를 돕고(숫자 밀집·스프레드시트형), none은 헤더 띠로만 구분하는 보더리스입니다(이미 경계가 있는 카드 내부 등).

에이전트역할작업 수
플래너작업 분해12
코더구현34
리뷰어코드 리뷰21
divider="grid" — 숫자 밀집형
에이전트역할작업 수
플래너작업 분해12
코더구현34
리뷰어코드 리뷰21
divider="none" — 보더리스

밀도 — density#

compact는 패딩을 space.2×space.3으로 줄여 한 화면에 더 많은 행을 — 표에 상주하는 파워유저·고밀도 데이터에 적합합니다.

에이전트역할작업 수
플래너작업 분해12
코더구현34
리뷰어코드 리뷰21
density="compact" — 고밀도

줄무늬 — striped#

짝수 행에 중립 배경을 넣어 넓고 긴 표의 행 추적을 돕습니다. 줄무늬가 구분 역할을 하므로 divider="grid"와 함께 쓰지 않습니다(줄무늬 OR 보더).

에이전트역할작업 수
플래너작업 분해12
코더구현34
리뷰어코드 리뷰21
문서봇문서화9
striped — 넓고 긴 스캔형

헤더 고정 — stickyHeader#

maxHeight로 세로 스크롤 영역을 만들면 헤더가 상단에 핀으로 고정됩니다 — 긴 표를 스크롤하며 컬럼 의미를 잃지 않습니다.

에이전트역할작업 수
플래너작업 분해12
코더구현34
리뷰어코드 리뷰21
문서봇문서화9
테스터검증18
배포봇릴리스5
감시봇모니터링27
stickyHeader + maxHeight="12rem"

변형은 직교합니다 — 의도에 맞게 조합하되, 아래 가이드를 따릅니다.

변형언제주의
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
같은 Table — 컨테이너 폭만 다름 (넓으면 표 · 좁으면 카드)
  • primaryColumn으로 한 컬럼을 카드 제목으로 승격합니다(라벨 없이 강조 — 보통 행을 식별하는 이름 컬럼).
  • 나머지 셀은 header를 라벨로 재사용합니다. header가 아이콘 등 복합 노드면 컬럼에 cardLabel로 짧은 텍스트 라벨을 따로 줍니다.
  • 전환 임계값은 컨테이너 폭 600px로 고정입니다(ADR-012 compact). 가변 임계값은 후속 단계에서 제공합니다.

컬럼 우선순위 — columns (비교형)#

컬럼 간 값을 나란히 비교하는 표는 카드화하면 비교가 깨집니다. responsive="columns"는 폭이 부족하면 priority가 낮은 컬럼부터 숨기고(첫 컬럼=식별자는 항상 유지) 숨긴 값은 행 펼치기로 상세에 노출합니다. 표 구조(컬럼 정렬·비교)를 보존하면서 좁은 화면에 맞춥니다. ResizeObserver로 컨테이너 폭을 측정하는 클라이언트 컴포넌트입니다.

에이전트 비교
에이전트역할작업 수상태
플래너작업 분해12실행 중
코더구현34대기
리뷰어코드 리뷰21완료
responsive="columns" — 좁으면 낮은 우선순위 컬럼 숨김 + 펼치기
  • priority높을수록 더 오래 유지됩니다(기본 0). 좁아질수록 낮은 우선순위 컬럼부터 숨고, 동률이면 왼쪽 컬럼이 남습니다.
  • 숨긴 값은 행 끝의 + 버튼(펼치기)으로 상세에 라벨↔값으로 노출됩니다.
  • 첫 컬럼은 행 식별자라 항상 보이며, 가로 스크롤이 생기면 sticky로 고정됩니다.

크기#

폭은 부모 100%, 좁은 화면에서는 래퍼가 가로 스크롤로 보호합니다. 셀 패딩은 기본 space.3×space.4(comfortable) — density="compact"space.2×space.3입니다.

상태#

에이전트작업 수
아직 실행된 에이전트가 없습니다
빈 상태 — emptyContent

행 hover는 surface-hover 배경 — 의사클래스로 처리됩니다.

Props#

Prop타입기본값설명
columnsreadonly TableColumn<T>[]컬럼 정의 배열 (아래 표)
datareadonly T[]행 데이터 — 비어 있으면 emptyContent 표시
rowKey(row: T, index: number) => string행 고유 키 — index 기반 키는 재정렬 시 위험해 명시를 강제한다
captionReactNode표 이름(접근성) — 제공 시 스크롤 래퍼도 키보드 region이 된다
emptyContentReactNode데이터가 없습니다데이터 0건일 때 표시할 내용
divider'rows' | 'grid' | 'none'rows테두리/구분선 스타일 — 기본 rows(가로 구분선만). grid·none 변형 제공
density'comfortable' | 'compact'comfortable밀도 — 기본 comfortable. compact는 패딩을 줄인 고밀도
stripedbooleanfalse줄무늬(zebra) — 짝수 행에 중립 배경. 넓고 긴 스캔형 표에 권장. divider="grid"와 동시 사용은 권장하지 않는다(줄무늬 OR 보더 — 중복 방지).
stickyHeaderbooleanfalse헤더 고정 — 세로 스크롤 시 헤더를 상단에 핀. 동작하려면 세로 스크롤 영역이 필요하다 → maxHeight로 활성화.
maxHeightstring세로 스크롤 영역 높이(CSS 값) — 초과 시 본문 스크롤. stickyHeader의 전제
responsive'scroll' | 'cards' | 'columns'scroll반응형 전략 — 기본 scroll(현행 가로 스크롤). cards는 좁은 컨테이너(<600px)에서 행→카드 스택.
primaryColumnstringresponsive="cards"에서 카드 제목으로 승격할 컬럼 key — 해당 셀은 라벨 없이 강조 렌더. 보통 행을 식별하는 컬럼(이름 등)을 지정한다.
refRef<HTMLDivElement>최외곽 스크롤 래퍼 <div>로 전달되는 ref (React 19 ref-as-prop)

TableColumn<T>:

Prop타입기본값설명
keystring데이터 키 또는 고유 컬럼 id — render 미지정 시 row[key] 원시값을 표시
headerReactNode헤더 셀 내용
alignTableAlign정렬 — 숫자는 right 권장 (기본 left)
widthstring컬럼 폭 (CSS 값)
render(row: T, rowIndex: number) => ReactNode커스텀 셀 렌더
cardLabelReactNoderesponsive="cards"/columns 모드에서 셀 앞·상세에 붙는 라벨 — 미지정 시 header를 재사용. header가 아이콘 등 복합 노드일 때 짧은 텍스트 라벨을 따로 줄 용도.
prioritynumberresponsive="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)
행 hovercolor.surface-hover
셀 패딩space.3 × space.4

관련#