DataGrid, DataSheet for React
npm i @axboot/datagridnpm i
npm run devOpen http://localhost:5173 with your browser to see the demo app.
# Unit tests (Vitest)
npm test
# Unit tests in watch mode
npm run test:watch
# Consumer compatibility test (install + cjs/esm/types check)
npm run test:library:consumers
# E2E tests (Playwright)
npm run test:e2e
# E2E tests with UI runner
npm run test:e2e:ui# Demo app bundle (Vite)
npm run build
# Publishable library bundle (CJS + ESM + types + style)
npm run build:library# Build dist/cjs, dist/esm, dist/types and dist/package.json
npm run build:library
# Dry-run package file list from dist
npm run pack:library
# Publish dist package manually
npm run publish:library- Workflow file:
.github/workflows/publish-npm.yml - Trigger: push tag
v*(example:v1.6.4) or manualworkflow_dispatch - Required secret:
NPM_TOKEN - Safety check: tag version must match
package.jsonversion
import '@axboot/datagrid/style.css';or
Add the code below to your project.
[role='ax-datagrid'] {
--axdg-primary-color: #3b82f6;
--axdg-header-bg: #f3f4f5;
--axdg-header-color: #222;
--axdg-header-font-weight: 500;
--axdg-header-hover-bg: #e2e5e5;
--axdg-header-group-bg: #e9e9e9;
--axdg-footer-bg: #f3f4f5;
--axdg-summary-bg: #eaeef6;
--axdg-border-color-base: #d2d5d9;
--axdg-border-color-light: #d2d5d9;
--axdg-border-radius: 4px;
--axdg-row-selector-color: #ffffff;
--axdg-body-bg: #ffffff;
--axdg-body-odd-bg: #f8f8f8;
--axdg-body-hover-bg: #f3f4f5;
--axdg-body-hover-odd-bg: #eeeeee;
--axdg-body-active-bg: #e6f6ff;
--axdg-body-color: #444;
--axdg-scroll-size: 11px;
--axdg-scroll-track-bg: #f9f9f9;
--axdg-scroll-thumb-radius: 6px;
--axdg-scroll-thumb-bg: #c0c1c5;
--axdg-scroll-thumb-hover-bg: #a1a3a6;
--axdg-loading-bg: rgba(163, 163, 163, 0.1);
--axdg-loading-color: rgba(0, 0, 0, 0.1);
--axdg-loading-second-color: #767676;
--axdg-page-number-active-border-radius: 4px;
}- codesandbox DEMO : https://codesandbox.io/p/devbox/basic-example-5ch6kt?embed=1&file=%2Fsrc%2FApp.tsx
import * as React from 'react';
import styled from '@emotion/styled';
import { AXDataGrid, AXDGColumn } from '@axboot/datagrid';
interface IListItem {
id: string;
title: string;
writer: string;
createAt: string;
}
const list = Array.from({ length: 1000 }).map((_, i) => ({
values: {
id: `ID_${i}`,
title: `title_${i}`,
writer: `writer_${i}`,
createAt: `2022-09-08`,
},
}));
function BasicExample() {
const [columns, setColumns] = React.useState<AXDGColumn<IListItem>[]>([
{ key: 'id', label: 'ID', width: 120 },
{
key: 'title',
label: '제목',
width: 260,
itemRender: ({ values }) => <>{values.writer} / {values.title}</>,
},
{ key: 'writer', label: '작성자', width: 120 },
{ key: 'createAt', label: '작성일', width: 140 },
]);
const [checkedRowKeys, setCheckedRowKeys] = React.useState<React.Key[]>([]);
return (
<Container>
<AXDataGrid<IListItem>
width={720}
height={420}
data={list}
columns={columns}
rowKey={'id'}
onChangeColumns={(columnIndex, { width, columns }) => {
console.log('onChangeColumns', columnIndex, width, columns);
setColumns(columns);
}}
rowChecked={{
checkedRowKeys,
onChange: (checkedIndexes, checkedRowKeys, checkedAll) => {
console.log('rowChecked changed', checkedIndexes, checkedRowKeys, checkedAll);
setCheckedRowKeys(checkedRowKeys);
},
}}
/>
</Container>
);
}
const Container = styled.div`
font-size: 13px;
`;
export default BasicExample;- Row data type is
AXDGDataItem<T>and the real domain model is always insideitem.values. AXDGColumn.keysupports bothstringandstring[].key: 'writer'key: ['user', 'profile', 'name'](nested value path)
itemRenderreceives both:value: current cell value bycolumn.keyvalues: full row model (T)
columns[i].leftis internal layout value computed byAXDataGrid; do not manage it manually.
<AXDataGrid
width={900}
height={500}
frozenColumnIndex={2}
columns={columns}
data={data}
/>frozenColumnIndex 이전 컬럼(0, 1)은 고정 영역으로 렌더링됩니다.
const columns: AXDGColumn<IListItem>[] = [
{
key: 'title',
label: '제목',
width: 240,
editable: true,
itemRender: ({ editable, value, handleSave, handleCancel }) => {
if (!editable) return <>{value}</>;
return (
<input
autoFocus
defaultValue={value}
onBlur={e => handleSave?.(e.target.value)}
onKeyDown={e => {
if (e.key === 'Enter') handleSave?.((e.target as HTMLInputElement).value);
if (e.key === 'Escape') handleCancel?.();
}}
/>
);
},
},
];
<AXDataGrid editable editTrigger={'dblclick'} columns={columns} data={data} width={700} height={400} />;<AXDataGrid
width={900}
height={560}
columns={columns}
data={rows}
sort={{
sortParams,
onChange: next => setSortParams(next),
}}
page={{
currentPage,
pageSize,
totalPages,
totalElements,
onChange: (nextPage, nextSize) => {
setCurrentPage(nextPage);
if (nextSize) setPageSize(nextSize);
},
}}
/>아래는 자주 사용하는 Props 중심 정리입니다. 타입의 최종 기준은 @axboot-datagrid/types.ts의 AXDGProps<T>입니다.
| Prop | Type | Description |
|---|---|---|
width |
number |
그리드 전체 너비 |
height |
number |
그리드 전체 높이 |
columns |
AXDGColumn<T>[] (width optional) |
컬럼 정의 |
| Prop | Type | Description |
|---|---|---|
data |
AXDGDataItem<T>[] |
행 데이터 (values 래핑 필수) |
rowKey |
React.Key | React.Key[] |
행 고유 키 필드 |
selectedRowKey |
React.Key | React.Key[] |
포커스된 행 키 |
rowChecked |
AXDGRowChecked<T> |
체크박스/라디오 선택 제어 (onChange 필수) |
getRowClassName |
(ri, item) => string | undefined |
행 단위 className 지정 |
rowSelection/selectedIds는 현재 API가 아닙니다.rowChecked를 사용해야 합니다.
| Prop | Type | Description |
|---|---|---|
headerHeight |
number |
헤더 높이 (기본 30) |
footerHeight |
number |
페이지네이션 푸터 높이 (기본 30) |
summaryHeight |
number |
summary 높이 (기본 30) |
itemHeight |
number |
본문 행 컨텐츠 높이 (기본 15) |
itemPadding |
number |
행 내부 패딩 (기본 7) |
frozenColumnIndex |
number |
고정 컬럼 경계 인덱스 |
showLineNumber |
boolean |
좌측 라인 번호 표시 |
variant |
'default' | 'vertical-bordered' |
스킨 변형 |
loading |
boolean |
전체 오버레이 로딩 |
spinning |
boolean |
바디 스피너 로딩 |
| Prop | Type | Description |
|---|---|---|
columnsGroup |
AXDGColumnGroup[] |
헤더 그룹 |
onChangeColumns |
(columnIndex, info) => void |
컬럼 폭/순서/그룹 변경 콜백 |
onChangeData |
(index, columnIndex, item, column) => void |
셀 편집 데이터 변경 콜백 |
editable |
boolean |
편집 모드 활성화 |
editTrigger |
'click' | 'dblclick' |
편집 진입 트리거 (기본 click) |
onClick |
(params) => void |
셀 클릭 이벤트 |
| Prop | Type | Description |
|---|---|---|
sort |
AXDGSortInfo |
정렬 상태/변경 콜백 |
columnSortable |
boolean |
컬럼 drag sort 제어 |
page |
AXDGPage |
페이지네이션 상태/콜백 |
summary |
{ columns, position } |
상/하단 summary 행 |
cellMergeOptions |
{ columnsMap } |
셀 병합 옵션 |
reorder |
AXDGReorderInfo<T> |
행 reorder 설정 |
msg |
{ emptyList?: string } |
커스텀 메시지 |
- rowChecked 속성 추가 (rowChecked > isRadio, rowChecked > disabled)
<AXDataGrid<IListItem>
width={containerWidth}
height={containerHeight}
headerHeight={35}
data={sortedList}
columns={columns}
onChangeColumns={(columnIndex, { width, columns }) => {
console.log('onChangeColumnWidths', columnIndex, width, columns);
setColumns(columns);
}}
rowChecked={{
disabled: (ri, item) => ri === 0,
isRadio: true,
checkedRowKeys: checkedKeys,
onChange: (ids, keys, selectedAll) => {
console.log('onChange rowSelection', ids, keys, selectedAll);
setCheckedKeys(keys);
},
}}
sort={{
sortParams,
onChange: sortParams => {
console.log('onChange: sortParams', sortParams);
setSortParams(sortParams);
},
}}
showLineNumber
rowKey={'nation'}
/>- columnsGroup 타입변경 기존 columnsIndex: []에서 start, end 지정 형태로 변경되었습니다.
[{ label: '묶음', groupStartIndex: 2, groupEndIndex: 4, align: 'center' }]- onChangeColumns 속성 변경
// onChangeColumns Type
onChangeColumns?: (
columnIndex: number | null,
info: {
width?: number;
columns: AXDGColumn<T>[];
columnsGroup?: AXDGColumnGroup[];
},
) => void;
// onChangeColumns에서 변경된 컬럼과 컬럼 그룹을 받을 수 있습니다
<AXDataGrid
/*...*/
onChangeColumns={(columnIndex, { columns, columnsGroup }) => {
console.log('onChangeColumnWidths', columnIndex, columns, columnsGroup);
setColumns(columns);
setColumnsGroup(columnsGroup);
}}
/>