컬럼 숨김과 복구 (Column Visibility)

헤더 툴박스에서 컬럼을 숨기고, 다른 컬럼 메뉴에서 다시 표시하거나 전체 복구하는 방법을 설명합니다.

#columnVisibility#hideable#controlled-state#user-customization
지원 버전: v1.0.6+검토일: 2026-09-07
LIVE DEMO컬럼 숨김과 복구 (Column Visibility) 인터랙티브 예제
인터랙티브 데모를 불러오는 중입니다…
GitHub
import * as React from 'react';
import { useMemo, useState } from 'react';
import { Button, Tag } from 'antd';
import { Eye, RotateCcw } from 'lucide-react';
import { BGrid } from 'beautiful-grid';
import type { BGridColumn, BGridColumnGroupNode, BGridDataQuery } from 'beautiful-grid';
import DataGridContainer from '../components/DataGridContainer';
import { useContainerSize } from '../hooks/useContainerSize';
import { t, exampleMsg } from './i18n';

interface OrderRow {
  orderNo: string;
  customer: string;
  region: string;
  status: string;
  owner: string;
  dueDate: string;
  amount: number;
}

const customers = ['Northwind', 'Contoso', 'Fabrikam', 'Adventure Works', 'Tailspin'];
const regions = [t('서울', 'Seoul'), t('부산', 'Busan'), t('대전', 'Daejeon'), t('광주', 'Gwangju')];
const statuses = [t('접수', 'Received'), t('처리 중', 'Processing'), t('출고', 'Shipped')];
const owners = [t('김서준', 'Alex Kim'), t('이하은', 'Jamie Lee'), t('박지후', 'Chris Park')];

const rows = Array.from({ length: 24 }, (_, index) => ({
  values: {
    orderNo: `ORD-${String(index + 1).padStart(4, '0')}`,
    customer: customers[index % customers.length],
    region: regions[index % regions.length],
    status: statuses[index % statuses.length],
    owner: owners[index % owners.length],
    dueDate: `2026-09-${String((index % 20) + 8).padStart(2, '0')}`,
    amount: 128000 + index * 17500,
  },
}));

const groups: BGridColumnGroupNode[] = [
  {
    id: 'order',
    label: t('주문 정보', 'Order'),
    children: ['orderNo', 'customer'],
  },
  {
    id: 'delivery',
    label: t('처리 정보', 'Fulfillment'),
    children: ['region', 'status', 'owner', 'dueDate'],
  },
];

export default function ColumnVisibilityExample() {
  const containerRef = React.useRef<HTMLDivElement>(null);
  const { width, height } = useContainerSize(containerRef);
  const [hiddenColumnIds, setHiddenColumnIds] = useState<string[]>(['owner']);
  const [query, setQuery] = useState<BGridDataQuery>({
    sortParams: [],
    filterParams: [],
  });
  const columns = useMemo<BGridColumn<OrderRow>[]>(
    () => [
      {
        id: 'orderNo',
        key: 'orderNo',
        label: t('주문 번호', 'Order No.'),
        width: 120,
        hideable: false,
        toolbox: true,
        filter: { type: 'text' },
      },
      {
        id: 'customer',
        key: 'customer',
        label: t('고객사', 'Customer'),
        width: 150,
        toolbox: true,
        filter: { type: 'text' },
      },
      {
        id: 'region',
        key: 'region',
        label: t('권역', 'Region'),
        width: 100,
        align: 'center',
        toolbox: true,
        filter: { type: 'values' },
      },
      {
        id: 'status',
        key: 'status',
        label: t('상태', 'Status'),
        width: 105,
        align: 'center',
        toolbox: true,
        filter: { type: 'values' },
      },
      {
        id: 'owner',
        key: 'owner',
        label: t('담당자', 'Owner'),
        width: 110,
        align: 'center',
        toolbox: true,
        filter: { type: 'values' },
      },
      {
        id: 'dueDate',
        key: 'dueDate',
        label: t('출고 예정일', 'Due date'),
        width: 120,
        align: 'center',
        toolbox: true,
        filter: { type: 'text' },
      },
      {
        id: 'amount',
        key: 'amount',
        label: t('주문 금액', 'Amount'),
        width: 130,
        align: 'right',
        toolbox: true,
        filter: { type: 'number' },
        itemRender: ({ value }) => `${Number(value).toLocaleString()}${t('원', ' KRW')}`,
      },
    ],
    [],
  );

  return (
    <>
      <div className='flex flex-wrap items-center justify-between gap-2 p-3 bg-slate-50 border border-slate-200 rounded-lg text-sm'>
        <div className='flex flex-wrap items-center gap-2'>
          <Tag
            data-testid='hidden-column-status'
            className='inline-flex items-center gap-1'
            color={hiddenColumnIds.length ? 'blue' : 'default'}
          >
            <Eye size={13} aria-hidden='true' />
            <span>{t('숨긴 컬럼', 'Hidden')} {hiddenColumnIds.length}</span>
          </Tag>
          <Tag>{t('정렬', 'Sort')} {query.sortParams.length}</Tag>
          <Tag>{t('필터', 'Filter')} {query.filterParams.length}</Tag>
          <span className='text-slate-500'>
            {hiddenColumnIds.length
              ? hiddenColumnIds.map(id => columns.find(column => column.id === id)?.label ?? id).join(', ')
              : t('모든 컬럼 표시 중', 'All columns visible')}
          </span>
        </div>
        <Button
          size='small'
          icon={<RotateCcw size={14} />}
          disabled={hiddenColumnIds.length === 0}
          onClick={() => setHiddenColumnIds([])}
        >
          {t('모두 표시', 'Show all')}
        </Button>
      </div>

      <DataGridContainer ref={containerRef}>
        <BGrid
          width={width}
          height={height}
          data={rows}
          columns={columns}
          msg={exampleMsg}
          columnGroups={groups}
          headerHeight={54}
          frozenColumnIndex={2}
          columnVisibility={{
            hiddenColumnIds,
            onChange: setHiddenColumnIds,
          }}
          dataControl={{
            mode: 'client',
            query,
            onChange: setQuery,
            multiSort: true,
          }}
          rowKey='orderNo'
          variant='vertical-bordered'
        />
      </DataGridContainer>
    </>
  );
}

기본 사용법

컬럼 숨김과 복구 기능은 BeautifulGrid 1.0.6부터 지원합니다.

columnVisibility를 켜면 각 컬럼 툴박스에 이 컬럼 숨기기가 추가됩니다. 숨긴 컬럼은 남아 있는 컬럼의 메뉴에서 다시 표시할 수 있습니다. 마지막 표시 컬럼은 숨길 수 없습니다. 위 라이브 데모처럼 컬럼의 toolbox와 filter를 함께 설정하면 같은 메뉴에서 정렬, 필터, 숨김을 모두 사용할 수 있습니다.

<BGrid
  width={800}
  height={420}
  columns={columns}
  data={data}
  columnVisibility
/>

숨김 상태 저장하기

사용자 설정을 저장하려면 컬럼마다 고유한 id를 지정하고 controlled 상태를 사용합니다.

const [hiddenColumnIds, setHiddenColumnIds] = useState<string[]>(['owner']);

<BGrid
  width={800}
  height={420}
  columns={columns}
  data={data}
  columnVisibility={{
    hiddenColumnIds,
    onChange: setHiddenColumnIds,
  }}
/>

특정 컬럼을 사용자가 숨기지 못하게 하려면 hideable: false를 설정합니다. API로 전달한 숨김 상태는 정렬·필터 조건을 제거하지 않으며, 컬럼을 다시 표시하면 이전 조건이 그대로 나타납니다.

const columns = [
  { id: 'orderNo', key: 'orderNo', label: '주문 번호', width: 120, hideable: false },
  { id: 'customer', key: 'customer', label: '고객사', width: 160 },
  { id: 'owner', key: 'owner', label: '담당자', width: 120 },
];

컬럼이 숨겨진 동안에는 드래그 컬럼 재배치가 비활성화됩니다. 모든 컬럼을 다시 표시하면 columnSortable 설정이 자동으로 복원됩니다.