임동욱 임동욱 08-18
feat: Table 컴포넌트 3종 추가
Figma 표 시안 9종(tbl-basic·tbl-list·tbl-form과 각각의 cell-head·cell-body)을
FoxTable / FoxTableRow / FoxTableCell 셋으로 옮겼다. 세 타입이 뼈대가 같고 여백·글자·
기본 정렬만 달라 한 벌로 충분하다.

진짜 
이라 스크린리더가 행·열을 읽어 주고 colSpan·rowSpan이 그대로 동작한다.
본문 행의 제목 칸은 그 줄의 이름이라 scope="row", 머리행 칸은 열 이름이라 scope="col"이
붙는다. 호출부는 행을 늘어놓기만 하면 되고 head 여부로 thead·tbody가 갈린다.

타입 차이를 클래스가 아니라 커스텀 프로퍼티로 내려보낸다. `.fox-table--basic
.fox-table-cell`처럼 후손 선택자를 쓰면 표 안에 표가 들어갔을 때 바깥 규칙이 안쪽까지
덮어쓴다 — 글머리 목록에서 겪은 것과 같은 문제다. 커스텀 프로퍼티는 안쪽 표가 자기
값으로 다시 덮으므로 그 일이 생기지 않는다.

좁은 화면 대응도 시안대로 넣었다. list는 머리행을 감추고 한 줄이 카드로 접히며, 이때
열 이름을 알 수 없으므로 칸이 label을 받아 글자로 보여 준다. form은 레이블이 입력 위로
올라가고 레이블 칸의 회색 바탕이 사라진다. basic은 시안에 모바일 변형이 없어 그대로 둔다.

승인된 비토큰 값: form 머리칸 최소 크기 12rem×4.8rem.

검증: 여백·바탕·글자·정렬 18항목이 시안과 일치(나머지 1건은 내 예상값 오류였고 코드가
맞다 — font/weight/medium은 SemiBold 600이다). 모바일에서 list 카드 접힘·열 이름 노출,
form 위아래 쌓임, basic 유지를 확인했다. sass 524규칙 · tsc · eslint 통과.

Co-Authored-By: Claude Opus 5 
@6cbc8be8523648b572e2ab14bb23fc92d40f289a
 
@fox/core/components/fox-table-cell/fox-table-cell.tsx (added)
+++ @fox/core/components/fox-table-cell/fox-table-cell.tsx
@@ -0,0 +1,83 @@
+"use client";
+
+import type { ReactNode } from "react";
+import { cx } from "../../utils";
+
+export type FoxTableCellAlign = "start" | "center" | "end";
+
+export interface FoxTableCellProps {
+  children?: ReactNode;
+  /** 참이면 `<th>`가 된다. 머리행 안에서는 주지 않아도 행이 채운다. */
+  head?: boolean;
+  align?: FoxTableCellAlign;
+  colSpan?: number;
+  rowSpan?: number;
+  /** 열 너비. `<col>` 없이 한 칸만 잡을 때 쓴다. */
+  width?: string | number;
+  /**
+   * 모바일에서 칸 앞에 붙는 열 이름. `list` 표가 카드로 접히면 머리행이 사라져서,
+   * 이 값이 없으면 무슨 값인지 알 수 없다.
+   */
+  label?: string;
+  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
+  hidden?: boolean;
+  /** 배치 조정용. */
+  className?: string;
+
+  /** FoxTableRow가 채운다 — 머리행인지. 직접 넘기지 않는다. */
+  inHead?: boolean;
+}
+
+const ALIGN_CLASS: Record<FoxTableCellAlign, string> = {
+  start: "fox-table-cell--start",
+  center: "fox-table-cell--center",
+  end: "fox-table-cell--end",
+};
+
+/**
+ * @fox 표의 칸. 머리칸이면 `<th>`, 아니면 `<td>`다.
+ *
+ * 본문 행에 놓인 머리칸은 그 줄의 이름이라 `scope="row"`가 붙는다 — 시안 basic 표의 첫
+ * 열이 그렇다. 머리행 안이면 열 이름이라 `scope="col"`이다.
+ *
+ * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
+ * (또는 개별 파티셜)로 한 번 불러와야 한다.
+ */
+export function FoxTableCell({
+  children,
+  head,
+  align,
+  colSpan,
+  rowSpan,
+  width,
+  label,
+  hidden = false,
+  className,
+  inHead = false,
+}: FoxTableCellProps) {
+  if (hidden) {
+    return null;
+  }
+
+  const isHead = head ?? inHead;
+  const Tag = isHead ? "th" : "td";
+
+  return (
+    <Tag
+      className={cx(
+        "fox-table-cell",
+        isHead ? "fox-table-cell--head" : "fox-table-cell--body",
+        align && ALIGN_CLASS[align],
+        className
+      )}
+      scope={isHead ? (inHead ? "col" : "row") : undefined}
+      colSpan={colSpan}
+      rowSpan={rowSpan}
+      style={width === undefined ? undefined : { inlineSize: width }}
+    >
+      {/* 카드로 접혔을 때만 보인다 — 표로 있을 때는 머리행이 이미 같은 말을 한다. */}
+      {label && <span className="fox-table-cell__label">{label}</span>}
+      <span className="fox-table-cell__content">{children}</span>
+    </Tag>
+  );
+}
 
@fox/core/components/fox-table-cell/index.ts (added)
+++ @fox/core/components/fox-table-cell/index.ts
@@ -0,0 +1,5 @@
+export {
+  FoxTableCell,
+  type FoxTableCellProps,
+  type FoxTableCellAlign,
+} from "./fox-table-cell";
 
@fox/core/components/fox-table-row/fox-table-row.tsx (added)
+++ @fox/core/components/fox-table-row/fox-table-row.tsx
@@ -0,0 +1,59 @@
+"use client";
+
+import {
+  Children,
+  Fragment,
+  cloneElement,
+  isValidElement,
+  type ReactElement,
+  type ReactNode,
+} from "react";
+import { cx } from "../../utils";
+
+export interface FoxTableRowProps {
+  children?: ReactNode;
+  /** 참이면 머리행이다. 안의 칸이 모두 `<th scope="col">`이 된다. */
+  head?: boolean;
+  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
+  hidden?: boolean;
+  /** 배치 조정용. */
+  className?: string;
+}
+
+/** 머리행이라는 사실을 칸에 내려 준다. 프래그먼트는 `Children.map`이 들어가지 않아 직접 내려간다. */
+function markCells(children: ReactNode): ReactNode {
+  return Children.map(children, (child) => {
+    if (!isValidElement(child)) {
+      return child;
+    }
+
+    if (child.type === Fragment) {
+      const fragment = child as ReactElement<{ children?: ReactNode }>;
+      return markCells(fragment.props.children);
+    }
+
+    if (typeof child.type === "string") {
+      return child;
+    }
+
+    return cloneElement(child as ReactElement<Record<string, unknown>>, { inHead: true });
+  });
+}
+
+/**
+ * @fox 표의 한 줄.
+ *
+ * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
+ * (또는 개별 파티셜)로 한 번 불러와야 한다.
+ */
+export function FoxTableRow({ children, head = false, hidden = false, className }: FoxTableRowProps) {
+  if (hidden) {
+    return null;
+  }
+
+  return (
+    <tr className={cx("fox-table-row", head && "fox-table-row--head", className)}>
+      {head ? markCells(children) : children}
+    </tr>
+  );
+}
 
@fox/core/components/fox-table-row/index.ts (added)
+++ @fox/core/components/fox-table-row/index.ts
@@ -0,0 +1,1 @@
+export { FoxTableRow, type FoxTableRowProps } from "./fox-table-row";
 
@fox/core/components/fox-table/fox-table.tsx (added)
+++ @fox/core/components/fox-table/fox-table.tsx
@@ -0,0 +1,85 @@
+"use client";
+
+import {
+  Children,
+  Fragment,
+  isValidElement,
+  type ReactElement,
+  type ReactNode,
+} from "react";
+import { cx } from "../../utils";
+import type { FoxTableRowProps } from "../fox-table-row";
+
+export type FoxTableType = "basic" | "list" | "form";
+
+export interface FoxTableProps {
+  /** `FoxTableRow`들. 머리행은 `head`를 주면 되고 순서는 신경 쓰지 않아도 된다. */
+  children?: ReactNode;
+  /**
+   * `basic`은 제목 열이 있는 상세표, `list`는 목록표, `form`은 레이블 + 입력표다.
+   * 여백·글자·기본 정렬이 이 값에 따라 달라진다.
+   */
+  type?: FoxTableType;
+  /** 표가 무엇을 담는지. `<caption>`으로 나가며 화면에는 보이지 않는다. */
+  caption?: string;
+  /** 참이면 렌더하지 않는다(DOM에 남지 않는다). */
+  hidden?: boolean;
+  /** 배치 조정용. */
+  className?: string;
+}
+
+type RowElement = ReactElement<FoxTableRowProps>;
+
+/** 프래그먼트 안까지 훑어 행을 모은다. */
+function collectRows(children: ReactNode): RowElement[] {
+  const rows: RowElement[] = [];
+  Children.forEach(children, (child) => {
+    if (!isValidElement(child)) {
+      return;
+    }
+    if (child.type === Fragment) {
+      const fragment = child as ReactElement<{ children?: ReactNode }>;
+      rows.push(...collectRows(fragment.props.children));
+      return;
+    }
+    rows.push(child as RowElement);
+  });
+  return rows;
+}
+
+/**
+ * @fox 표. 진짜 `<table>`이라 스크린리더가 몇 행 몇 열인지 읽어 주고 `colSpan`·`rowSpan`이
+ * 그대로 동작한다.
+ *
+ * 호출부는 행을 늘어놓기만 하면 된다 — 머리행(`head`)은 `<thead>`로, 나머지는 `<tbody>`로
+ * 알아서 갈린다.
+ *
+ * 좁은 화면에서는 `list`가 한 줄씩 카드로 접히고 `form`은 레이블이 입력 위로 올라간다
+ * (시안의 device 축). 그 전환은 CSS가 화면 폭을 보고 하므로 프롭이 없다.
+ *
+ * ⚠️ 스타일은 이 파일이 import하지 않는다 — 호스트 앱이 `@use "@fox/styles/components"`
+ * (또는 개별 파티셜)로 한 번 불러와야 한다.
+ */
+export function FoxTable({
+  children,
+  type = "basic",
+  caption,
+  hidden = false,
+  className,
+}: FoxTableProps) {
+  if (hidden) {
+    return null;
+  }
+
+  const rows = collectRows(children);
+  const headRows = rows.filter((row) => row.props.head);
+  const bodyRows = rows.filter((row) => !row.props.head);
+
+  return (
+    <table className={cx("fox-table", `fox-table--${type}`, className)}>
+      {caption && <caption className="fox-table__caption">{caption}</caption>}
+      {headRows.length > 0 && <thead className="fox-table__head">{headRows}</thead>}
+      {bodyRows.length > 0 && <tbody className="fox-table__body">{bodyRows}</tbody>}
+    </table>
+  );
+}
 
@fox/core/components/fox-table/index.ts (added)
+++ @fox/core/components/fox-table/index.ts
@@ -0,0 +1,1 @@
+export { FoxTable, type FoxTableProps, type FoxTableType } from "./fox-table";
@fox/core/components/index.ts
--- @fox/core/components/index.ts
+++ @fox/core/components/index.ts
@@ -30,6 +30,9 @@
 export * from "./fox-select";
 export * from "./fox-select-option";
 export * from "./fox-select-option-item";
+export * from "./fox-table";
+export * from "./fox-table-cell";
+export * from "./fox-table-row";
 export * from "./fox-tag";
 export * from "./fox-tag-list";
 export * from "./fox-text-area";
@fox/dev-test/component-registry.tsx
--- @fox/dev-test/component-registry.tsx
+++ @fox/dev-test/component-registry.tsx
@@ -42,6 +42,9 @@
 import { FoxBadge } from "../core/components/fox-badge";
 import { FoxBadgeDot } from "../core/components/fox-badge-dot";
 import { FoxBadgeGroup } from "../core/components/fox-badge-group";
+import { FoxTable } from "../core/components/fox-table";
+import { FoxTableCell } from "../core/components/fox-table-cell";
+import { FoxTableRow } from "../core/components/fox-table-row";
 import styles from "./dev-test.module.scss";
 
 export interface ComponentExample {
@@ -2545,4 +2548,112 @@
       },
     ],
   },
+  {
+    id: "fox-table",
+    name: "FoxTable",
+    description:
+      "Figma 시안 9종(tbl-basic · tbl-list · tbl-form과 각각의 행·칸)을 FoxTable / FoxTableRow / FoxTableCell 셋으로 옮겼습니다. 진짜 <table>이라 스크린리더가 행·열을 읽어 주고 colSpan·rowSpan이 그대로 동작합니다. 머리행은 head만 주면 <thead>로 알아서 갈립니다. 창을 768px 아래로 좁히면 list는 카드로 접히고 form은 레이블이 입력 위로 올라갑니다.",
+    variants: [
+      {
+        label: "basic — 제목 열이 있는 상세표",
+        node: (
+          <FoxTable caption="basic 표 예시">
+            <FoxTableRow head>
+              <FoxTableCell>제목</FoxTableCell>
+              <FoxTableCell>제목</FoxTableCell>
+              <FoxTableCell>제목</FoxTableCell>
+              <FoxTableCell>제목</FoxTableCell>
+            </FoxTableRow>
+            <FoxTableRow>
+              <FoxTableCell head>제목</FoxTableCell>
+              <FoxTableCell>길어서 2줄 되는 내용 긴 내용</FoxTableCell>
+              <FoxTableCell>내용</FoxTableCell>
+              <FoxTableCell>승인</FoxTableCell>
+            </FoxTableRow>
+            <FoxTableRow>
+              <FoxTableCell head>제목</FoxTableCell>
+              <FoxTableCell colSpan={2}>두 칸을 합친 내용 (colSpan)</FoxTableCell>
+              <FoxTableCell>검토</FoxTableCell>
+            </FoxTableRow>
+          </FoxTable>
+        ),
+      },
+      {
+        label: "list — 목록표. 좁히면 카드로 접힙니다",
+        node: (
+          <FoxTable type="list" caption="list 표 예시">
+            <FoxTableRow head>
+              <FoxTableCell width={64}>번호</FoxTableCell>
+              <FoxTableCell>제목</FoxTableCell>
+              <FoxTableCell width={120}>작성자</FoxTableCell>
+              <FoxTableCell width={120}>등록일</FoxTableCell>
+            </FoxTableRow>
+            {[1, 2, 3].map((n) => (
+              <FoxTableRow key={n}>
+                <FoxTableCell label="번호">{n}</FoxTableCell>
+                <FoxTableCell label="제목" align="start">
+                  목록 제목 {n}
+                </FoxTableCell>
+                <FoxTableCell label="작성자">홍길동</FoxTableCell>
+                <FoxTableCell label="등록일">2026-08-18</FoxTableCell>
+              </FoxTableRow>
+            ))}
+          </FoxTable>
+        ),
+      },
+      {
+        label: "form — 레이블 + 입력. 좁히면 위아래로 쌓입니다",
+        node: (
+          <FoxTable type="form" caption="form 표 예시">
+            <FoxTableRow>
+              <FoxTableCell head>레이블</FoxTableCell>
+              <FoxTableCell>내용</FoxTableCell>
+            </FoxTableRow>
+            <FoxTableRow>
+              <FoxTableCell head>
+                <FoxFormLabel as="span" requirement="required">
+                  레이블
+                </FoxFormLabel>
+              </FoxTableCell>
+              <FoxTableCell>
+                <InputStage>
+                  <FoxInput size="md" placeholder="내용을 입력하세요." aria-label="내용" />
+                </InputStage>
+              </FoxTableCell>
+            </FoxTableRow>
+            <FoxTableRow>
+              <FoxTableCell head>레이블</FoxTableCell>
+              <FoxTableCell>
+                <FoxBadgeGroup size="md">
+                  <FoxBadge color="primary" type="pastel">
+                    태그
+                  </FoxBadge>
+                  <FoxBadge color="success" type="pastel">
+                    태그
+                  </FoxBadge>
+                </FoxBadgeGroup>
+              </FoxTableCell>
+            </FoxTableRow>
+          </FoxTable>
+        ),
+      },
+      {
+        label: "칸 정렬 (align) — 표 기본값을 이깁니다",
+        node: (
+          <FoxTable type="list" caption="정렬 예시">
+            <FoxTableRow head>
+              <FoxTableCell align="start">start</FoxTableCell>
+              <FoxTableCell align="center">center</FoxTableCell>
+              <FoxTableCell align="end">end</FoxTableCell>
+            </FoxTableRow>
+            <FoxTableRow>
+              <FoxTableCell align="start">왼쪽</FoxTableCell>
+              <FoxTableCell align="center">가운데</FoxTableCell>
+              <FoxTableCell align="end">오른쪽</FoxTableCell>
+            </FoxTableRow>
+          </FoxTable>
+        ),
+      },
+    ],
+  },
 ];
 
@fox/styles/_fox-table-cell.scss (added)
+++ @fox/styles/_fox-table-cell.scss
@@ -0,0 +1,83 @@
+// FoxTableCell — 시안: 통합관리자페이지 디자인시스템(KE9UILWhB8qTBe14uXUn4F)
+//                       tbl-basic-cell-head (425:5694) · tbl-basic-cell-body (425:5701)
+//                       tbl-list-cell-head (391:4116) · tbl-list-cell-body (391:4150)
+//                       tbl-form-cell-head (391:4307) · tbl-form-cell-body (391:4337)
+//
+// 마크업 계약: `_fox-table.scss` 상단 참고.
+//
+// 여섯 시안이 한 컴포넌트다 — 바탕(머리 회색 / 본문 흰색)과 아래 선이 모두 같고, 여백·
+// 글자·기본 정렬만 표 타입에 따라 달라진다. 그 값은 표가 커스텀 프로퍼티로 내려보낸다.
+//
+// 열 이름(`__label`)은 카드로 접혔을 때만 보인다 — 표로 있을 때는 머리행이 이미 같은 말을
+// 한다.
+//
+// 토큰이 아닌 값:
+//   - line-height / letter-spacing: 시안 텍스트 스타일의 값이나 Figma가 변수로
+//     export하지 않는다.
+
+@use "abstracts" as fox;
+
+.fox-table-cell {
+  padding-inline: var(--fox-table-cell-padding-inline);
+  border-block-end: fox.border(1) solid fox.color(border-neutral-subtler);
+  color: fox.color(font-neutral-default);
+  font-family: fox.font-family(body);
+  font-size: fox.font-size(body-md);
+  font-weight: fox.font-weight(regular);
+  line-height: 1.5;
+  letter-spacing: -0.025em;
+  text-align: var(--fox-table-body-align);
+  vertical-align: middle;
+
+  &--head {
+    min-inline-size: var(--fox-table-head-min-inline-size);
+    min-block-size: var(--fox-table-cell-min-block-size);
+    padding-block: var(--fox-table-head-padding-block);
+    background: fox.color(surface-neutral-gray);
+    font-family: var(--fox-table-head-font-family);
+    font-size: var(--fox-table-head-font-size);
+    font-weight: var(--fox-table-head-font-weight);
+    line-height: var(--fox-table-head-line-height);
+    text-align: var(--fox-table-head-align);
+  }
+
+  &--body {
+    padding-block: var(--fox-table-body-padding-block);
+    background: fox.color(surface-neutral-default);
+  }
+
+  // 칸이 직접 정한 정렬은 표 기본값을 이긴다.
+  &--start { text-align: start; }
+  &--center { text-align: center; }
+  &--end { text-align: end; }
+
+  // 표로 있을 때는 머리행이 열 이름을 말하므로 감춘다.
+  &__label {
+    display: none;
+  }
+
+  @include fox.mobile {
+    // 카드로 접힌 줄 안에서만 열 이름이 보인다.
+    .fox-table--list & {
+      display: flex;
+      gap: fox.gap(3);
+      align-items: baseline;
+      text-align: start;
+    }
+
+    .fox-table--list &__label {
+      display: block;
+      flex-shrink: 0;
+      color: fox.color(font-neutral-subtle);
+      font-family: fox.font-family(title);
+      font-size: fox.font-size(heading-2xsm);
+      font-weight: fox.font-weight(bold);
+      line-height: 1.4;
+    }
+
+    .fox-table--list &__content {
+      flex: 1 0 0;
+      min-inline-size: 0;
+    }
+  }
+}
 
@fox/styles/_fox-table-row.scss (added)
+++ @fox/styles/_fox-table-row.scss
@@ -0,0 +1,14 @@
+// FoxTableRow — 시안: 통합관리자페이지 디자인시스템(KE9UILWhB8qTBe14uXUn4F)
+//                      tbl-*-row-head · tbl-*-row-body
+//
+// 마크업 계약: `_fox-table.scss` 상단 참고.
+//
+// 줄 자체는 모양을 갖지 않는다 — 시안에서 바탕과 아래 선이 모두 칸에 걸려 있다.
+// 좁은 화면에서 카드가 될 때만 줄이 테두리를 갖는다(그 규칙은 `_fox-table.scss`에 있다).
+
+@use "abstracts" as fox;
+
+.fox-table-row {
+  // 마지막 줄도 아래 선을 갖는다(시안). 칸이 그리므로 여기서는 둘 것이 없다.
+  border: none;
+}
 
@fox/styles/_fox-table.scss (added)
+++ @fox/styles/_fox-table.scss
@@ -0,0 +1,139 @@
+// FoxTable — 시안: 통합관리자페이지 디자인시스템(KE9UILWhB8qTBe14uXUn4F)
+//                   tbl-basic (425:5781) · tbl-list (391:4283) · tbl-form (391:4389)
+//
+// 마크업 계약 (React 밖 소비자용):
+//   <table class="fox-table fox-table--basic">
+//     <caption class="fox-table__caption">…</caption>          <!-- 선택 · 눈에 안 보인다 -->
+//     <thead class="fox-table__head">
+//       <tr class="fox-table-row fox-table-row--head">
+//         <th class="fox-table-cell fox-table-cell--head" scope="col">…</th>
+//       </tr>
+//     </thead>
+//     <tbody class="fox-table__body">
+//       <tr class="fox-table-row">
+//         <th class="fox-table-cell fox-table-cell--head" scope="row">…</th>
+//         <td class="fox-table-cell fox-table-cell--body">…</td>
+//       </tr>
+//     </tbody>
+//   </table>
+//
+// 세 타입은 뼈대가 같고 여백·글자·기본 정렬만 다르다. 그 차이를 클래스가 아니라 커스텀
+// 프로퍼티로 내려보낸다 — 칸에 `.fox-table--basic .fox-table-cell`처럼 후손 선택자를 쓰면
+// 표 안에 표가 들어갔을 때 바깥 표의 규칙이 안쪽까지 덮어쓴다. 커스텀 프로퍼티는 안쪽
+// 표가 자기 값으로 다시 덮으므로 그 문제가 없다.
+//
+// 좁은 화면에서 `list`는 한 줄이 카드로 접히고 `form`은 레이블이 입력 위로 올라간다
+// (시안 device 축). 표 요소를 `display: block`으로 바꿔 만드는데, 그러면 표 의미가 사라져
+// 스크린리더가 행·열을 읽지 못한다. 그래서 `list`의 칸은 `label`을 함께 받아 카드에서
+// 열 이름을 글자로 보여 준다.
+//
+// 토큰이 아닌 값:
+//   - form 머리칸의 최소 크기 12rem×4.8rem: 시안 값이나 Figma가 변수로 export하지
+//     않는다(사용자 승인).
+//   - line-height / letter-spacing: 시안 텍스트 스타일의 값이나 Figma가 변수로
+//     export하지 않는다.
+//   - border-collapse / table-layout / display 전환: 구조 규칙.
+
+@use "abstracts" as fox;
+
+.fox-table {
+  // 타입이 칸에 내려보내는 값. 기본은 시안 basic이다.
+  --fox-table-cell-padding-inline: #{fox.padding(5)};
+  --fox-table-head-padding-block: #{fox.padding(3)};
+  --fox-table-body-padding-block: #{fox.padding(6)};
+  --fox-table-head-font-size: #{fox.font-size(heading-2xsm)};
+  --fox-table-head-font-family: #{fox.font-family(title)};
+  --fox-table-head-font-weight: #{fox.font-weight(bold)};
+  --fox-table-head-line-height: 1.4;
+  --fox-table-head-align: center;
+  --fox-table-body-align: center;
+  --fox-table-head-min-inline-size: 0;
+  --fox-table-cell-min-block-size: 0;
+
+  inline-size: 100%;
+  border-collapse: collapse;
+  border-block-start: fox.border(1) solid fox.color(border-neutral-subtler);
+
+  // 목록표는 줄이 촘촘하다.
+  &--list {
+    --fox-table-body-padding-block: #{fox.padding(3)};
+  }
+
+  // 입력표는 레이블 열이 왼쪽에 서고 여백이 넓다.
+  &--form {
+    --fox-table-cell-padding-inline: #{fox.padding(6)};
+    --fox-table-head-padding-block: #{fox.padding(6)};
+    --fox-table-body-padding-block: #{fox.padding(3)};
+    --fox-table-head-font-size: #{fox.font-size(label-md)};
+    --fox-table-head-font-family: #{fox.font-family(body)};
+    --fox-table-head-font-weight: #{fox.font-weight(medium)};
+    --fox-table-head-line-height: 1;
+    --fox-table-head-align: start;
+    --fox-table-body-align: start;
+    // 시안 값이나 변수로 export되지 않는다 — 파일 상단 참고.
+    --fox-table-head-min-inline-size: 12rem;
+    --fox-table-cell-min-block-size: 4.8rem;
+  }
+
+  // 표가 무엇을 담는지 스크린리더에만 알린다.
+  &__caption {
+    position: absolute;
+    inline-size: fox.border(1);
+    block-size: fox.border(1);
+    margin: calc(-1 * #{fox.border(1)});
+    padding: 0;
+    overflow: hidden;
+    clip-path: inset(50%);
+    white-space: nowrap;
+  }
+
+  // ── 좁은 화면 ─────────────────────────────────────────────────────────────
+  @include fox.mobile {
+    // 목록표는 한 줄이 카드가 된다. 머리행은 카드마다 열 이름이 붙으므로 감춘다.
+    &--list {
+      border-block-start: none;
+
+      .fox-table__head {
+        display: none;
+      }
+
+      .fox-table__body,
+      .fox-table-row,
+      .fox-table-cell {
+        display: block;
+        inline-size: 100%;
+      }
+
+      .fox-table-row {
+        border-block-end: fox.border(1) solid fox.color(border-neutral-subtler);
+      }
+
+      .fox-table-cell {
+        border-block-end: none;
+      }
+    }
+
+    // 입력표는 레이블이 입력 위로 올라간다.
+    &--form {
+      .fox-table__body,
+      .fox-table-row,
+      .fox-table-cell {
+        display: block;
+        inline-size: 100%;
+      }
+
+      .fox-table-row {
+        border-block-end: fox.border(1) solid fox.color(border-neutral-subtler);
+      }
+
+      .fox-table-cell {
+        border-block-end: none;
+      }
+
+      .fox-table-cell--head {
+        min-inline-size: 0;
+        background: fox.color(surface-neutral-default);
+      }
+    }
+  }
+}
@fox/styles/components.scss
--- @fox/styles/components.scss
+++ @fox/styles/components.scss
@@ -38,3 +38,6 @@
 @use "fox-badge";
 @use "fox-badge-dot";
 @use "fox-badge-group";
+@use "fox-table";
+@use "fox-table-row";
+@use "fox-table-cell";
Add a comment
List