Extending the grid
모든 override seam 한 장 카탈로그 + veto 패턴(onCellKeyDown/onCellPointerDown) + 내장 클립보드 재사용.
확장의 두 가지 길
이 그리드는 "상태와 라우팅만 소유하고 렌더는 위임"하는 얇은 인프라입니다. 그래서 확장은 두 갈래입니다.
- 정책 seam — 훅 옵션과
column.meta로 동작의 규칙을 바꿉니다. 선택을 같은 컬럼으로 제약하거나(transformSelection), 특정 셀만 편집 가능하게 하거나(isCellEditable), fill 값을 직접 계산합니다(getFillValue). 그리드의 키/포인터 라우팅은 그대로 두고, 그 안에서 무엇을 허용하고 어떻게 계산하는지만 바꿉니다. - veto 패턴 —
onCellKeyDown/onCellPointerDown으로 그리드 내장 처리 자체를 가로챕니다.preventGridDefault()를 부르면 그 키/포인터에 대한 내장 동작(내비·편집·클립보드·선택 시작)을 전부 끄고, 소비자가 통째로 대체합니다.
먼저 모든 seam을 한 장으로 모은 카탈로그를, 그다음 veto 패턴과 클립보드 재사용을 다룹니다.
Override seam 카탈로그
영역별로 정리한 전수 표입니다. 각 seam의 상세 동작과 더 많은 예제는 연결된 딥 페이지를 참고하세요.
useDataGrid — 뷰 상태
View state에서 다룹니다. loading/error는 Root prop이 아니라 useDataGrid 옵션입니다.
Prop
Type
selection — 선택 정책
Selection model에서 다룹니다. 모든 정책은 useDataGridSelection(table, options)의 옵션입니다.
Prop
Type
editing — 편집 라이프사이클
Editing model에서 다룹니다. useDataGridEditing(table, options)의 옵션입니다.
Prop
Type
fillHandle — 자동 채우기
Clipboard & Fill에서 다룹니다. useDataGridFillHandle(table, options)의 옵션입니다.
Prop
Type
scrollToActive — 활성 셀 추적 스크롤
useDataGridScrollToActive(table, options)의 옵션입니다. 옵트인 — 호출하지 않으면 비용 0(effect 미등록).
Prop
Type
column.meta — 컬럼 단위 동작
Cell merging·Editing·View state에서 다룹니다. TanStack ColumnMeta에 declaration merging으로 얹힌 키입니다 — column.meta에 그대로 적습니다.
Prop
Type
Root — veto · ARIA · 크기
<DataGrid.Root>의 prop입니다. onCellKeyDown/onCellPointerDown이 veto 패턴의 진입점입니다.
Prop
Type
클립보드 헬퍼 — 내장 직렬화 재사용
패키지 루트에서 export하는 순수 함수입니다. 커스텀 클립보드/키 리맵에서 그리드 내장과 동일한 규칙을 재사용할 때 씁니다.
Prop
Type
veto 패턴 — 내장 처리 가로채기
정책 seam이 규칙을 바꾸는 거라면, veto는 그리드가 그 키/포인터를 처리하는 것 자체를 끕니다.
onCellKeyDown/onCellPointerDown은 그리드 내장 처리가 돌기 전에 호출되고, 콜백 안에서 ctx.preventGridDefault()를
부르면 그 이벤트에 대한 내장 동작이 전부 취소됩니다. react-data-grid의 onCellKeyDown + preventGridDefault 패턴과 같습니다.
두 콜백 모두 포털 자손에서 올라온 이벤트는 제외됩니다. 소비자가 editor를 Popover/Modal로 띄우면 그쪽 input의 native 처리에 맡깁니다(시스템 가드 우선).
키 리맵 — onCellKeyDown
ctx는 { focused, preventGridDefault }입니다. focused는 현재 활성 셀 좌표(없으면 null),
preventGridDefault()를 부르면 그 키에 대한 내비·편집 진입·클립보드·undo를 전부 끕니다.
아래는 Enter를 "편집 진입" 대신 "행 상세 열기"로 리맵하는 예입니다.
import { useDataGrid, useDataGridSelection, useDataGridEditing, DataGrid } from '@featuring-corp/data-grid';
function Grid({ data }: { data: Row[] }) {
const table = useDataGrid<Row>({ data, columns, getCoreRowModel: getCoreRowModel(), getRowId: (r) => r.id });
const selection = useDataGridSelection(table);
const editing = useDataGridEditing(table, { selection, onCellEdit });
return (
<DataGrid.Root
table={table}
selection={selection}
editing={editing}
onCellKeyDown={(e, { focused, preventGridDefault }) => {
if (e.key === 'Enter' && focused) {
// 그리드 내장 Enter(편집 진입)를 취소하고 소비자 동작으로 대체.
preventGridDefault();
e.preventDefault();
openRowDetail(focused.rowId);
}
}}
>
<DataGrid.Header />
<DataGrid.Body />
</DataGrid.Root>
);
}preventGridDefault()를 부르지 않으면 그리드 내장 처리가 평소대로 이어집니다 — 즉 특정 키만 가로채고 나머지는
그대로 두는 게 기본 사용 패턴입니다.
포인터 가로채기 — onCellPointerDown (행 reorder 드래그)
ctx는 { preventGridDefault }이고, 두 번째 인자로 눌린 셀 좌표 coord가 옵니다.
preventGridDefault()를 부르면 그 pointerdown에 대한 셀 선택 시작·드래그·grid focus가 전부 취소됩니다 —
특정 컬럼(예: 드래그 핸들 컬럼)에서만 자체 인터랙션을 구현할 때 씁니다.
<DataGrid.Root
table={table}
selection={selection}
onCellPointerDown={(e, coord, { preventGridDefault }) => {
// 'dragHandle' 컬럼에서 누르면 셀 선택 대신 행 reorder 드래그를 시작.
if (coord.columnId === 'dragHandle') {
preventGridDefault(); // 셀 선택/드래그/focus 취소
startRowDrag(coord.rowId, e);
}
}}
>
<DataGrid.Header />
<DataGrid.Body />
</DataGrid.Root>커스텀 클립보드 / 키 리맵
내장 복사를 리맵하거나, "선택 영역 내보내기" 버튼을 따로 만들 때, 그리드 내장과 동일한 직렬화 규칙을 재사용합니다.
getActiveRange로 대상 range를 고르고(비연속 다중선택에서 active range), serializeRangeToTsv로 TSV를 만듭니다 —
meta.getCopyValue 존중·control 컬럼 제외·병합 covered 셀 빈칸 처리가 그대로 적용됩니다.
역방향(붙여넣기 파싱)은 parseTsv입니다.
import {
useDataGridSelection,
getActiveRange,
serializeRangeToTsv,
parseTsv,
type DataGridSelection,
type DataGridInstance,
} from '@featuring-corp/data-grid';
// "선택 영역을 TSV로 내보내기" — 내장 Cmd+C와 동일 규칙 재사용.
function exportSelection<T>(table: DataGridInstance<T>, selection: DataGridSelection): string | null {
const range = getActiveRange(selection);
if (!range) return null;
return serializeRangeToTsv(table, range); // getCopyValue/control 제외/병합 처리 동일
}
// 붙여넣을 TSV를 2D 배열로 파싱(serializeRangeToTsv의 역연산).
const matrix = parseTsv('a\tb\nc\td'); // → [['a','b'], ['c','d']]onCellKeyDown과 묶으면 키 리맵도 내장 규칙으로 처리할 수 있습니다 — 예를 들어 Cmd+Shift+C를 "표시값 복사"로
추가하되 직렬화는 serializeRangeToTsv에 맡깁니다.
<DataGrid.Root
table={table}
selection={selection}
editing={editing}
onCellKeyDown={(e, { preventGridDefault }) => {
if ((e.metaKey || e.ctrlKey) && e.shiftKey && e.key.toLowerCase() === 'c') {
preventGridDefault();
e.preventDefault();
const tsv = exportSelection(table, selection);
if (tsv) navigator.clipboard.writeText(tsv);
}
}}
>
{/* ... */}
</DataGrid.Root>커스텀 에디터 / 셀
에디터 UI는 그리드가 소유하지 않습니다 — column.cell 함수가 직접 렌더합니다. 그리드와 소비자 에디터의 유일한 접점은
useDataGridCellEdit 훅입니다. 이 헤드리스 escape hatch로 현재 셀의 편집 상태(isEditing/initialValue/trigger/
prefillChar/saveStatus)를 읽고 commit/cancel을 호출합니다 — TextInput·Select·DatePicker 어느 것이든 연결할 수 있습니다.
자세한 사용법과 패키지 기본 <DataGrid.TextEditor>(IME·키·blur 내장)는 Editing model에서 다룹니다.
degradation contract — 소비자 콜백 throw 처리
소비자 콜백이 throw할 때 그리드가 어떻게 강등하는지는 콜백이 어디서 호출되는가에 따라 갈립니다.
- 이벤트 핸들러 경로(가드됨) —
transformSelection·isCellSelectable·onCellEdit·onBulkEdit·onPaste·equals·parseValue·getFillValue·meta.fill·doubleClickAction등은 키/포인터/paste 이벤트 핸들러 안에서 호출됩니다. 여기서 동기 throw가 새면 호스트 앱이 크래시하므로, 그리드가 격리해 안전하게 강등하고(거부/무시/해당 편집 fail) 개발 모드에서 1회 경고합니다. 비동기 검증은 throw 대신 반환 Promise를 reject 하세요(onCellEdit의 record-on-confirm). - 렌더 경로(소비자 책임) —
meta.cell·meta.skeleton·meta.colSpan/rowSpan처럼 React 렌더 중 호출되는 콜백은 그리드가 try/catch로 가둘 수 없습니다(렌더 트리에서 던지면 React가 트리를 unmount). 이쪽은 소비자가 React error boundary로 감싸 처리해야 합니다.
이벤트 핸들러 콜백 throw → 그리드가 격리 → 안전 강등 + dev 경고
렌더 경로 콜백 throw → 소비자 error boundary 책임다음 단계
- Selection model —
transformSelection/isCellSelectable/controlled 정책 seam. - Editing model —
useDataGridCellEdit헤드리스 에디터·async record-on-confirm. - Clipboard & Fill — TSV 직렬화·
getFillValue·doubleClickAction. - Cell merging —
colSpan/rowSpandense 좌표. - API reference — 공개 export 전수 표.