컴포넌트
Table
데이터를 행과 열로 표시합니다.
설치
pnpm dlx ply-ui add table공통 설치 설정을 먼저 적용합니다.
사용법
Header/Body 안에 Row를 구성하고 Head와 Cell을 구분합니다.
Caption으로 표의 목적을 설명하고 열 제목에 scope="col"을 지정합니다.
구성
| 구성 요소 | 역할 |
|---|---|
Table | 행과 열을 묶는 표입니다. |
TableCaption | 표의 이름이나 설명입니다. |
TableHeader / TableBody | 제목 행과 데이터 행 영역입니다. |
TableRow | 하나의 행입니다. |
TableHead | 제목 셀입니다. scope로 행 또는 열 제목을 지정합니다. |
TableCell | 데이터 셀입니다. |
좁은 영역에서의 동작
Table은 가로 스크롤 영역을 기본으로 포함합니다. 넓은 표가 페이지 전체를 밀어내지 않고, 키보드로 스크롤 영역에 접근할 수 있습니다. containerProps는 바깥 영역, 나머지 속성과 ref는 실제 table에 전달합니다.
구현 코드
components/ui/table.tsx
import type { ComponentProps } from "react";
import { cx } from "../../lib/cx";
import "./table.css";
export type TableProps = ComponentProps<"table"> & {
/** 표의 의미와 ref는 table에 남기고, 가로 스크롤 영역만 별도로 설정합니다. */
containerProps?: ComponentProps<"div">;
};
export function Table({ className, containerProps, ...props }: TableProps) {
return (
<div
role="region"
aria-label={props["aria-label"] ?? "표 가로 스크롤"}
tabIndex={0}
{...containerProps}
className={cx("rbx-table-container", containerProps?.className)}
>
<table {...props} className={cx("rbx-table", className)} />
</div>
);
}
export function TableHeader({ className, ...props }: ComponentProps<"thead">) {
return <thead {...props} className={cx("rbx-table-header", className)} />;
}
export function TableBody({ className, ...props }: ComponentProps<"tbody">) {
return <tbody {...props} className={cx("rbx-table-body", className)} />;
}
export function TableRow({ className, ...props }: ComponentProps<"tr">) {
return <tr {...props} className={cx("rbx-table-row", className)} />;
}
export function TableHead({ className, ...props }: ComponentProps<"th">) {
return <th {...props} className={cx("rbx-table-head", className)} />;
}
export function TableCell({ className, ...props }: ComponentProps<"td">) {
return <td {...props} className={cx("rbx-table-cell", className)} />;
}
export function TableCaption({
className,
...props
}: ComponentProps<"caption">) {
return <caption {...props} className={cx("rbx-table-caption", className)} />;
}
components/ui/table.css
@layer theme, base, components, utilities;
@layer components.ply-base, components.ply;
@layer components.ply {
/* table — semantic HTML composition. */
.rbx-table {
width: 100%;
border-collapse: collapse;
text-align: start;
}
.rbx-table-head,
.rbx-table-cell {
white-space: nowrap;
padding: 14px 16px;
border-bottom: 1px solid var(--rbx-color-stroke-default);
}
.rbx-table-head {
/* th의 브라우저 기본 가운데 정렬을 표의 시작 정렬에 맞춥니다. */
text-align: inherit;
color: var(--rbx-color-content-muted);
font-size: 0.875rem;
font-weight: 600;
}
.rbx-table-caption {
text-align: start;
padding: 12px;
color: var(--rbx-color-content-default);
font-size: 0.875rem;
}
.rbx-table-container {
width: 100%;
max-width: 100%;
min-width: 0;
overflow-x: auto;
overscroll-behavior-x: contain;
}
.rbx-table-container:focus-visible {
outline-offset: -3px;
}
}