세로 구분선 (Variant)

variant prop으로 본문과 요약 셀의 세로 구분선 표시 여부를 전환하고 적용 범위를 확인합니다.

#variant#default#vertical-bordered#borders#summary
검토일: 2026-08-19
LIVE DEMO세로 구분선 (Variant) 인터랙티브 예제
인터랙티브 데모를 불러오는 중입니다…
GitHub
import { t } from './i18n';
import * as React from 'react';
import { BGrid, type BGridColumn, type BGridDataItem, type BGridProps, type BGridSummaryColumn } from 'beautiful-grid';
import { Segmented } from 'antd';
import DataGridContainer from '../components/DataGridContainer';
import { useContainerSize } from '../hooks/useContainerSize';

interface SalesRow {
  id: string;
  product: string;
  category: string;
  quantity: number;
  amount: number;
}

type GridVariant = NonNullable<BGridProps<SalesRow>['variant']>;

const categories = [t('하드웨어', 'Hardware'), t('소프트웨어', 'Software'), t('서비스', 'Service')];

const data: BGridDataItem<SalesRow>[] = Array.from({ length: 30 }, (_, index) => ({
  values: {
    id: `ORD-${String(index + 1).padStart(3, '0')}`,
    product: `${t('상품', 'Product')} ${index + 1}`,
    category: categories[index % categories.length],
    quantity: (index % 5) + 1,
    amount: 28000 + index * 3500,
  },
}));

const columns: BGridColumn<SalesRow>[] = [
  { key: 'id', label: t('주문번호', 'Order Number'), width: 100, align: 'center' },
  { key: 'product', label: t('상품명', 'Product Name'), width: 180 },
  { key: 'category', label: t('분류', 'Category'), width: 120, align: 'center' },
  { key: 'quantity', label: t('수량', 'Quantity'), width: 90, align: 'right' },
  {
    key: 'amount',
    label: t('금액', 'Amount'),
    width: 140,
    align: 'right',
    itemRender: ({ values }) => `${values.amount.toLocaleString('ko-KR')}${t('원', 'KRW')}`,
  },
];

const summaryColumns: BGridSummaryColumn<SalesRow>[] = [
  { columnIndex: 0, align: 'center', itemRender: () => <strong>{t('합계', 'Total')}</strong> },
  {
    columnIndex: 3,
    align: 'right',
    itemRender: ({ data }) => data.reduce((sum, item) => sum + item.values.quantity, 0),
  },
  {
    columnIndex: 4,
    align: 'right',
    itemRender: ({ data }) => `${data.reduce((sum, item) => sum + item.values.amount, 0).toLocaleString('ko-KR')}${t('원', 'KRW')}`,
  },
];

const variantOptions: Array<{ value: GridVariant; label: string; description: string }> = [
  { value: 'default', label: 'default', description: t('본문과 요약 셀의 세로 구분선 생략', 'Omit vertical separator between body and summary cell') },
  { value: 'vertical-bordered', label: 'vertical-bordered', description: t('본문과 요약 셀의 세로 구분선 표시', 'Show vertical separator between body and summary cell') },
];

export default function VariantExample() {
  const [variant, setVariant] = React.useState<GridVariant>('default');
  const containerRef = React.useRef<HTMLDivElement>(null);
  const { width, height } = useContainerSize(containerRef);

  return (
    <div className='flex min-h-0 flex-col gap-3'>
      <div className='flex flex-wrap items-center justify-between gap-3 rounded-lg border border-slate-200 bg-slate-50 p-3 text-sm text-slate-700'>
        <div>
          <strong className='block text-slate-900'>{t('세로 구분선 Variant', 'Vertical Border Variant')}</strong>
          <span className='text-xs text-slate-500'>{t('본문과 하단 합계 행에서 세로 구분선의 표시 여부를 비교해 보세요.', 'Compare whether the vertical border is displayed in the body and bottom summary rows.')}</span>
        </div>

        <Segmented
          aria-label={t('세로 구분선 variant 선택', 'Select Vertical Separator Variant')}
          value={variant}
          options={variantOptions.map(({ value, label }) => ({ value, label }))}
          onChange={value => setVariant(value as GridVariant)}
        />
      </div>

      <p className='m-0 text-xs text-slate-500' aria-live='polite'>
        {t('현재 설정:', 'Current Setting:')} <code>variant=&quot;{variant}&quot;</code> —{' '}
        {variantOptions.find(option => option.value === variant)?.description}
      </p>

      <DataGridContainer ref={containerRef}>
        <BGrid<SalesRow>
          width={width}
          height={height}
          columns={columns}
          data={data}
          rowKey='id'
          showLineNumber
          frozenColumnIndex={1}
          variant={variant}
          summary={{ position: 'bottom', rows: [{ columns: summaryColumns }] }}
        />
      </DataGridContainer>
    </div>
  );
}

1. variant가 바꾸는 것

BGrid의 variant prop은 그리드 본문과 Summary 셀의 세로 테두리 표현을 선택합니다. 데이터, 컬럼, 정렬, 선택 같은 동작은 바꾸지 않습니다.

값 표현 권장 용도
default 본문 셀 사이의 세로 구분선을 생략한 기본 스타일 행 단위 탐색이 중심인 일반 목록
vertical-bordered 본문과 Summary의 각 셀 오른쪽에 세로 구분선 표시 열 경계를 빠르게 구분해야 하는 밀도 높은 표

값을 생략하면 default가 적용됩니다.


2. 라이브 예제

위의 선택 버튼으로 두 값을 전환해 본문과 하단 합계 행의 세로 구분선을 비교할 수 있습니다. 고정 컬럼을 함께 사용해도 같은 variant가 고정 영역과 스크롤 영역에 일관되게 적용됩니다.

핵심 설정은 다음과 같습니다.

const [variant, setVariant] = useState<'default' | 'vertical-bordered'>('default');

<BGrid
  columns={columns}
  data={data}
  variant={variant}
  summary={{
    position: 'bottom',
    rows: [{ columns: summaryColumns }],
  }}
/>;

variant는 그리드 셀의 세로 구분선 표시 방식이며, scrollbar.variant의 native | classic | modern과는 서로 다른 설정입니다. 스크롤바 모양은 스크롤바 설정 가이드를 참고하세요.


3. 테마와 함께 사용하기

vertical-bordered의 선 색상은 --bgrid-border-color-light를 사용하며, 값이 없으면 --bgrid-border-color-base로 대체됩니다. 서비스 테마에 맞춰 선 색상을 바꿀 때는 그리드 wrapper에서 CSS 변수를 재정의합니다.

.report-grid {
  --bgrid-border-color-light: #cbd5e1;
}

선의 대비를 조정한 뒤에는 일반 행, hover/선택 상태, Summary 행에서 컬럼 경계를 충분히 구분할 수 있는지 함께 확인하세요.