ComponentsP3 본문

DataGrid

편집형 데이터 그리드 — 정렬·행 선택·인라인 편집·클라이언트 페이징을 갖춘 표. 정적 표는 Table, 인터랙션이 필요하면 DataGrid. 비제어 defaultData + onDataChange(불변) (DK WizDataTable 사양의 절제된 1차 승격).

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

한눈에#

정렬·행 선택·인라인 편집·클라이언트 페이징을 갖춘 편집형 데이터 그리드입니다 — 정적 표는 Table, 인터랙션이 필요하면 DataGrid.

에이전트 작업 현황 — 셀 더블클릭 또는 Enter로 편집
담당완료
토큰 SSOT 정리planner6
달력 컴포넌트 구현coder14
접근성 키보드 경로 검수reviewer4
문서 포털 데모 작성coder9
회귀 테스트 보강tester7
  • 정렬·선택·인라인 편집·페이징
  • APG Data Grid(role=grid)
  • 비제어 defaultData
  • pageSize로 Pagination 합성

정렬 헤더 클릭(asc→desc→해제)·셀 더블클릭/Enter로 편집·완료 체크박스 즉시 토글 — 직접 조작해 보세요

함수 prop(rowKey)이 필수라 서버 MDX에서 직접 전달할 수 없어 데모 래퍼로 컬럼·rowKey를 주입합니다(DatePickerDemo 패턴). 샘플 5행, 정렬 가능 컬럼(작업·공수)과 편집기(text·select·number·checkbox)가 섞여 있습니다.

사용 시점#

인라인 편집·정렬·선택·페이징이 필요한 운영 표면 DataGrid — 정적 표시나 페이지 컨트롤만이면 다른 컴포넌트입니다.

쓴다
에이전트 작업 현황 — 셀 더블클릭 또는 Enter로 편집
담당완료
토큰 SSOT 정리planner6
달력 컴포넌트 구현coder14

운영 표에서 인라인 편집·헤더 정렬·행 선택·클라이언트 페이징 중 하나라도 필요할 때

대신 Table

읽기 전용으로 정적 표시만 할 때(가벼운 마크업)

대신 Pagination

페이지 이동 컨트롤만 따로 필요할 때(DataGrid는 pageSize로 합성)

아래 ## 변형의 비교표가 Table과의 선택 기준을 상세히 정리합니다.

플레이그라운드#

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

이름역할
김위즈플래너
이코드코더
박리뷰리뷰어
import { DataGrid } from '@wds/ui-web';

<DataGrid columns={columns} defaultData={members} rowKey={(row) => row.id} />

변형#

행 선택 데모 — 에이전트 작업 현황
담당완료
토큰 SSOT 정리planner6
달력 컴포넌트 구현coder14
접근성 키보드 경로 검수reviewer4
문서 포털 데모 작성coder9
회귀 테스트 보강tester7
selectable — 첫 열 체크박스 + 헤더 전체 선택(indeterminate)
페이징 데모 — 에이전트 작업 현황
담당완료
토큰 SSOT 정리planner6
달력 컴포넌트 구현coder14
pageSize — 하단 Pagination 합성 + 클라이언트 페이징

pageSize를 주면 하단에 Pagination이 합성되고 페이지 단위로 행을 잘라 보여줍니다. 정렬은 전체 데이터 기준이라 페이지가 바뀌어도 정렬 순서가 유지됩니다. stickyHeader를 켜면 세로 스크롤 시 헤더가 고정됩니다.

Table과의 선택 기준#

기준TableDataGrid
용도정적 표시 — 읽기 전용 데이터인라인 편집·정렬·선택이 필요한 운영 표
정렬소비자 책임(YAGNI)헤더 클릭 sortable 내장
행 선택없음selectable 체크박스 + 전체 선택
편집없음editor(text/number/select/checkbox) 인라인
페이징소비자 책임pageSize로 Pagination 합성

읽기 전용 표는 가벼운 Table을 쓰고, 편집·정렬·선택 중 하나라도 필요하면 DataGrid를 씁니다.

범위 제외(백로그) — rowspan 셀 병합 · 하위행(트리/확장) · 서버 페이징은 이번 1차 승격 범위 밖입니다. 서버 페이징이 필요하면 현재는 소비자가 defaultData를 페이지 단위로 갈아끼우는 방식으로 대응합니다.

크기#

폭은 부모 100%, 좁은 화면에서는 래퍼가 가로 스크롤로 보호합니다(caption이 있으면 그 스크롤 래퍼가 키보드 region이 됩니다). 셀 패딩은 space.3×space.4 단일 밀도이고, stickyHeader의 기본 컨테이너 높이는 24rem(약 10행)으로 소비자가 재정의할 수 있습니다.

상태#

빈 상태 데모 — 에이전트 작업 현황
담당완료
집계된 작업이 없습니다
빈 상태 — emptyContent
  • 행 hovercolor.surface-hover 배경
  • 선택 행color.surface-selected(hover보다 우선)
  • 편집 셀 포커스color.primary 아웃라인, 편집 모드 입력은 input.border-focus 보더
  • 정렬 활성 헤더aria-sort + color.primary 화살표(asc는 180° 회전)
  • 빈 데이터colSpan 전체 폭에 emptyContent

Props#

Prop타입기본값설명
columnsReadonlyArray<DataGridColumn<T>>컬럼 정의 배열 (아래 표)
defaultDataReadonlyArray<T>[]초기 행 데이터 (비제어) — 편집 확정 시 내부 상태만 갱신
onDataChange(rows: T[]) => void셀 편집 확정 통지 — 항상 새 배열·새 행 객체(불변)
rowKey(row: T, index: number) => string행 고유 키 — index 기반 키는 정렬 시 위험해 명시를 강제 (필수)
selectablebooleanfalse첫 열 체크박스 + 헤더 전체 선택(indeterminate)
onSelectionChange(keys: string[]) => void선택 행 키 통지 — 전체 데이터 기준(페이지 무관)
pageSizenumber지정 시 하단 Pagination 합성 + 클라이언트 페이징
stickyHeaderbooleanfalse세로 스크롤 시 헤더 고정
captionReactNode표 이름(접근성) — 제공 시 스크롤 래퍼도 키보드 region이 됨
emptyContentReactNode'데이터가 없습니다'데이터 0건 표시 내용
selectAllLabelstring'전체 선택'헤더 전체 선택 체크박스 aria-label
selectRowLabel(row: T, index: number) => string'{rowKey} 행 선택'행 선택 체크박스 aria-label

DataGridColumn<T>:

Prop타입기본값설명
keystring데이터 키 또는 컬럼 id — render 미지정 시 row[key] 원시값 표시
headerReactNode헤더 셀 내용
align'left' | 'center' | 'right'셀 정렬 — 숫자는 right 권장
widthstring컬럼 폭 (CSS 값)
sortablebooleanfalse헤더 버튼 클릭으로 asc → desc → 해제 순환 정렬
editor'text' | 'number' | 'select' | 'checkbox'checkbox는 즉시 토글, 나머지는 편집 모드 진입
optionsReadonlyArray<DataGridSelectOption>editor: 'select' 전용 옵션 목록 ({ value, label })
render(row: T, rowIndex: number) => ReactNode커스텀 셀 렌더 (편집기 없는 컬럼)

접근성#

APG Data Grid 패턴입니다 — role="grid" + 셀 roving tabindex로 그리드 전체가 단일 탭 스톱이 됩니다. 내부 위젯(정렬 버튼·체크박스)은 탭 순서에서 빠지고(tabIndex=-1) 포커스는 셀이 가지며 Enter/Space가 위임됩니다. 헤더는 <th scope="col"> + aria-sort, 페이징 시 DOM에 없는 행 수를 aria-rowcount/aria-rowindex로 보고합니다.

동작
Tab그리드 진입/이탈 — 마지막 포커스 셀(없으면 헤더 첫 셀) 하나만 탭 순서에 포함
셀 단위 포커스 이동(헤더 행 포함) — 경계에서 클램프, 순환 없음
Home / End행의 첫/마지막 셀
Ctrl+Home / Ctrl+End그리드 첫 셀(헤더)/마지막 셀
PageUp / PageDown이전/다음 페이지로 이동(pageSize 지정 시) — 셀 좌표 유지·클램프
정렬 헤더 셀 Enter / Spaceasc → desc → 해제 순환
선택 셀 Space / Enter행 선택 토글 · 헤더 선택 셀은 전체 선택 토글
checkbox 편집 셀 Space / Enter값 즉시 토글(편집 모드 없음)
편집 셀 Enter편집 모드 진입 — 입력으로 포커스 이동 (text/number/select)
편집 셀 더블클릭편집 모드 진입
편집 중 Enter확정(commit) + 셀로 포커스 복귀
편집 중 Escape취소 — 원값 유지 + 셀로 포커스 복귀 (편집 재진입 차단)
편집 중 blur확정 (Enter 확정 직후 blur 중복은 1회 가드)
  • 편집 중에는 그리드 내비가 꺼집니다 — 화살표는 입력 캐럿 이동에 쓰이고, Escape/Enter로 셀에 복귀한 뒤 다시 내비합니다
  • 클릭한 셀이 roving 탭 스톱이 됩니다 — Tab으로 나갔다 돌아와도 마지막 위치가 유지됩니다
  • number 편집은 빈 값·숫자 아님이면 조용히 취소(원값 유지)
  • 좁은 화면 가로 스크롤 래퍼는 caption이 있으면 role="region" + tabIndex=0으로 키보드 조작 가능

토큰#

component 토큰 없이 Table·Input·Checkbox 어휘와 semantic을 직접 소비합니다(신설 기준 §4 미충족).

속성토큰
헤더color.surface-muted(배경) · color.text-muted · border-strong(하단)
color.text · 구분선 color.border · 패딩 space.3 × space.4
행 hovercolor.surface-hover
선택 행color.surface-selected
정렬 활성color.primary(화살표)
인라인 에디터input.bg/fg/border-focus · radius.sm
편집 셀 포커스color.focus-ring(아웃라인)
캡션color.text-muted · font-size.caption
모션duration.fast + ease.standard

관련#