Components
Table
구조화된 데이터를 행/열로 표시. 툴바(검색·필터·액션)와 테이블 카드를 분리 배치.
Platform: Web · Desktop only. 모바일에서는 List + Item 카드 형태로 변환된다.
Mobile
테이블 자체는 모바일에서 사용하지 않는다. 동일 데이터를 세로 카드 리스트로 재구성한다.
변환 규칙
- 각 row → 한 장의 카드.
List로 감싸고 각 항목을Item으로 표현 - Primary identifier (테이블의 가장 왼쪽 컬럼, 예: name + avatar) →
ItemMedia+ItemContenttitle - Secondary 필드 (email, role, status 등) →
ItemContentdescription으로 인라인 노출. 2개를 초과하면 ItemContent 내부에 줄바꿈으로 stack - Trailing 액션 (테이블 row actions) →
ItemActionsslot에 placement. 액션이 3개 이상이면 DropdownMenu Mobile (Action Sheet)로 묶음 - 선택 가능 row: 행 전체를
Pressable로 감싸고 ≥44pt 높이 확보 — Item Mobile 참고
Toolbar (검색·필터·정렬)
- 검색 input → 리스트 상단 sticky text-field로 배치
- 필터/정렬 셀렉터 → 단일 select은 Select Mobile (BottomSheet), 복합 필터는 MultiSelect Mobile (Full BottomSheet)
- 테이블 헤더의 컬럼 정렬 기능 → 별도 "정렬" BottomSheet로 분리 (기준 + 방향 선택)
- Bulk 액션 toolbar → 다중 선택 시 화면 하단에 floating action bar 노출 (선택 카운트 + actions)
Pagination
- 데스크탑의 page indicator 대신 infinite scroll 또는 "더 보기" 버튼 패턴 사용
- 페이지 단위 navigation이 필수일 때만 하단 페이지 선택기 유지
빈 상태
- 카드 리스트 영역 가운데 placeholder (아이콘 + 한 줄 설명 + CTA). 데스크탑 빈-테이블 empty state와 동일 라벨 사용
Preview
Anatomy
툴바와 테이블 카드를 항상 분리 배치한다.
Toolbar (optional)
├─ TextField — 이름·이메일 검색
├─ Button (outlined) — DropdownMenu 필터 트리거
├─ DropdownMenu — 역할 필터 (전체 / Admin / Member)
└─ Button (primary) — 주요 액션 (팀원 초대 등)
Table card
├─ thead — 컬럼 헤더 (bg-stone-50, caption1Medium)
│ └─ 정렬 가능한 th — 클릭 시 asc ↔ desc 토글
└─ tbody
└─ tr × N
├─ Avatar — 이니셜 fallback (Radix Avatar)
├─ body text — 이름 body1Medium · 메타 body2Regular
├─ Badge — subtle · neutral (역할·상태 표시)
└─ Row Actions (행 우측 고정)
├─ 2개 이하 — Ghost icon button × 2 (Pen + Trash2), h-8 w-8
└─ 3개 이상 — Ghost icon button (MoreHorizontal) → DropdownMenuTable card는 overflow-x-auto를 기본으로 사용한다. 컬럼이 많은 표는 table에 min-w-*를 지정해 카드 안에서 가로 스크롤되게 하고, 오른쪽 컬럼이 잘리지 않도록 한다.
Primitives
테이블 내부에서 사용하는 컴포넌트들:
| 위치 | 컴포넌트 | 스타일 |
|---|---|---|
| 검색 | TextField | rounded-md border-stone-200, body1Regular, focus:border-brown-800 |
| 필터 트리거 | Button (outlined) | rounded-lg border-stone-200 bg-transparent, button2Medium |
| 필터 메뉴 | DropdownMenu | 선택 항목에 Check 아이콘 |
| 주요 액션 | Button (primary) | rounded-full bg-brown-800, button2Medium — 테이블 툴바의 초대/추가(+) 버튼에 한해 rounded-full 사용 |
| 프로필 | Avatar | Radix Avatar.Root + Avatar.Fallback, 32×32 |
| 역할·상태 | Badge (subtle · neutral) | rounded-full bg-stone-100, caption1Medium text-stone-600 |
Row Actions
행 단위 액션은 수에 따라 두 가지 패턴으로 나눈다.
- 2개 이하 (수정·삭제): Ghost icon button을 행 우측에 직접 배치
- 3개 이상 (또는 계층이 필요한 경우):
MoreHorizontal(⋯) 버튼 하나로 줄이고 DropdownMenu 사용
2개 이하 — 인라인 아이콘 버튼
3개 이상 — MoreHorizontal 드롭다운
규칙
| 요소 | 스펙 |
|---|---|
| 인라인 버튼 크기 | h-8 w-8 Ghost button, rounded-lg |
| 버튼 간격 | gap-0.5 — 아이콘 버튼 사이 최소 간격 |
| 아이콘 크기 | w-4 h-4 |
| 수정 버튼 | text-stone-400 hover:bg-stone-100 hover:text-stone-600 |
| 삭제 버튼 (인라인) | text-rose-400 hover:bg-rose-50 hover:text-rose-600 |
| 수정 중 행 배경 | bg-stone-50 — 수정 중임을 시각적으로 구분 |
| 수정 중 입력 필드 | TextField, px-3 py-1.5 rounded-md border-stone-200, focus:border-brown-800 |
| 수정 중 확인 버튼 | Check 아이콘, text-brown-800 hover:bg-stone-100 |
| 수정 중 취소 버튼 | X 아이콘, text-stone-400 hover:bg-stone-100 hover:text-stone-600 |
| 드롭다운 트리거 | MoreHorizontal Ghost button h-8 w-8, 열린 상태 data-[state=open]:bg-stone-100 |
| 드롭다운 정렬 | align="end" — 항상 행 우측 기준 |
| 드롭다운 파괴적 항목 | Separator로 분리 후 하단, text-rose-500 hover:bg-rose-50 |
Inline Add Row
표에서 여러 항목을 연속으로 추가해야 하는 경우 Dialog를 열지 않고 tbody 최상단에 추가 행을 인라인으로 표시한다.
- Do: 툴바의 주요 액션 버튼은 인라인 추가 행을 열고, 추가 성공 후에도 행을 유지한 채 입력값만 비운다.
- Do: 추가 행은 수정 중 행과 같은
bg-stone-50배경을 사용한다. - Do: 입력 필드는 Table 내부 TextField 규칙과 동일하게
h-8,body2Regular,border-stone-200,focus:border-brown-800을 사용한다. - Do: 확인은
Check, 취소는X아이콘 버튼을 사용하고 Row Actions의h-8 w-8규칙을 따른다. - Do:
Enter는 저장,Escape는 취소로 동작하게 한다. - Don't: 단순한 행 추가를 위해 Dialog를 띄우지 않는다. 반복 추가 플로우에서 사용자의 손을 불필요하게 멈추게 만든다.
Token Mapping
| 요소 | Token |
|---|---|
| thead 배경 | stone-50 — TableRow 컴포넌트 사용 시 thead 안의 행은 bg-transparent로 덮어써야 함 |
| thead 텍스트 | caption1Medium, stone-400 |
| 행 구분선 | 1px solid stone-100 — 가로만 |
| 셀 패딩 | px-4 py-2 |
| 이름 텍스트 | body1Medium, stone-700 |
| 보조 텍스트 | body2Regular, stone-400 |
| hover 행 | stone-50 |
| 빈 상태 | body2Regular, stone-300 |
A11y
<th scope="col">헤더 명시- 정렬 버튼에
aria-sort="ascending" | "descending"권장 - 검색 결과 변경 시
aria-live="polite"권장
Do / Don't
- Do: 툴바(검색·필터·버튼)는 테이블 카드 바깥에 독립 배치
- Do: 역할·상태는 Badge (subtle · neutral) 사용
- Do: 숫자 컬럼은 우측 정렬 +
tabular-nums - Do:
TableRow를thead안에도 사용할 경우,[thead_&]:bg-transparent [thead_&]:hover:bg-transparent로 행의 기본bg-white가 thead 배경을 덮지 않게 처리 - Do: 행 액션이 2개 이하면 인라인 아이콘 버튼, 3개 이상이면
MoreHorizontal+ DropdownMenu - Don't: 행 액션 버튼에
size="icon"(h-10) 사용 금지 — 표 안에서는h-8 w-8Ghost button 사용 - Don't: 세로 구분선(
border-inline-start) 사용 금지 — 가로선만 허용 - Don't: 모바일 좁은 뷰에서 Table 남용 →
ListItem스택으로 대체 - Don't: 중첩 Table 금지
