# Bone Flow #048 Table Specification v1.0

Classification: Phase 3 / Display UI  
Current Runtime: BoneTable 1.0.16  
Formal HTML Functional Class: `bf-table`

## 1. Responsibility

Table displays structured row data in columns and may host registered Bone Flow UI components inside cells. It does not own #049 Grid editing, #073 Pagination navigation, #121 Timeline control, or #002 Joint behavior.

## 2. Table options

`caption / columns / rows / showHeader / striped / hover / bordered / compact / showEmptyRows / displayRowCount / emptyText / theme / inheritParent / ariaLabel`.

Themes: `light / dark / neon`.

### Table Runtime Property Schema

`BoneTable.getPropertySchema()` / `getPropertyDefaults()` / `getPropertyDefinition(key)` are the formal Table Property APIs. `inheritParent` is a formal boolean Property with default `true`. It controls **Table itself -> parent element** layout and is independent from Cell Renderer `snapToCell`. When `true`, the root uses `bone-table--inherit-parent`, `data-inherit-parent="true"`, `width:100%`, and `max-width:100%`. When `false`, the root uses `bone-table--free`, `data-inherit-parent="false"`, `display:inline-block`, `width:auto`, and `max-width:100%`; the inner Table uses `width:auto`. The Functional Class attribute is `data-table-inherit-parent="true|false"`.

## 3. Column contract

A column has `key / label / align / width / cellElement`.

- `key`: required, unique
- `align`: `left / center / right`
- `width`: `auto` or CSS numeric length using `px / % / rem / em / ch`
- `cellElement`: optional column-level Cell Renderer default

## 4. Row contract

Rows are plain objects. `$cells.<columnKey>` may override the Cell Renderer configuration for one cell.

Plain cell values use `textContent`; row data is never executed as HTML.

## 5. Cell Element contract

`cellElement = { renderer, props, snapToCell }`

- `renderer`: renderer ID / Component ID / registered alias / className
- `props`: plain object passed to the renderer
- `snapToCell`: boolean, default `true`

## 6. Cell Renderer Registry

Built-ins: `plain / 017 / 018 / 020 / 021 / 029 / 054`.

Public registry APIs include `registerCellRenderer / unregisterCellRenderer / getCellRenderer / listCellRenderers / hasCellRenderer`.

Unknown/unavailable renderers use safe text fallback. #017 Text receives a Table-generated unique DOM id when no explicit Text id is supplied, preventing empty/duplicate ids across repeated rows and multiple Table instances.

## 7. Property Schema contract

A Renderer may register `propertySchema` as an array or provider function. Supported field types are `text / number / boolean / select / textarea / json`. Nested property paths are supported.

The Table Property Editor generates only the selected renderer's Property controls. It does not embed that component's Preview, Smoke, Validation, Completion, or unrelated page UI.


## 8. Empty-row display

`displayRowCount` is a non-negative integer minimum display-row count (0 = automatic). When `showEmptyRows` is true, missing rows are padded as value-less rows; real rows are never truncated.

`showEmptyRows` is Boolean and defaults to `true`.

- `true`: rows whose visible data values are all empty remain as table rows. Normal Text/Label/Shape renderers are suppressed for an empty value, leaving the Table cell/grid structure.
- `false`: rows whose visible data values are all empty are removed from the rendered tbody.
- `$cells` renderer configuration does not make a row non-empty.
- A Cell Renderer may declare `renderEmpty:true` to draw structural UI even when the cell value is empty. #054 Display Timeline uses this contract so `items=[]` still draws its timeline/grid. The built-in #029 NumberBox renderer uses the same contract: voucher mode keeps the voucher rules visible while the numeric value remains null.

## 9. Runtime-owned Schema

#054 Display Timeline uses `BoneDisplayTimeline.getPropertySchema()` as the source of truth. #048 must not duplicate #054's Property inventory.

`timeAxisMode` formal values are `all / group-first / none`. `showLabels` remains #054's compatibility gate.

## 10. group-first consumer rule

For `timeAxisMode="group-first"`, #048 supplies sequential `groupIndex=0,1,2...` values across #054 cells in the same Table column. A row-level `$cells.<columnKey>.props.groupIndex` explicitly supplied by the caller takes priority for that cell.

## 11. Post-layout contract

A Cell Renderer may return `afterLayout()` from `mount(ctx)`. #048 executes it only after the completed Table has been attached to the host DOM.

#054 uses this hook to perform formal `render()` against the actual cell width. Width changes are observed and cause a controlled rerender. #048 must not use a click or selection action as a layout trigger.

## 12. Snap-to-cell contract

`snapToCell:true` removes Table cell padding and fits the renderer host to the cell width. `false` preserves normal cell padding.

For #054, #048 supplies `snapToParent:true` when needed but leaves #054 height and internal geometry to the #054 Runtime.

## 13. Future UI extension

Future UI components register adapters with `BoneTable.registerCellRenderer()`. #048 must not require a per-component branch for each new UI. Renderer alias collisions are rejected.

## 14. Functional Class

`bf-table` is the single normal-use HTML Functional Class. HTML attributes provide the core Table options; Cell Renderer configuration is carried through the JSON `columns` / `rows` structures.

## 15. Security and validation

- Plain values are text-only
- Invalid options/columns/rows/property schemas are rejected
- Duplicate column keys are rejected
- Unknown UI does not execute raw HTML

## 16. QA / Completion

Smoke and Validation cover Runtime, Functional Class, Cell Renderer behavior, Property Schema, safe fallback, #054 formal-schema integration, group-first coordination, and post-layout behavior.

Completion requires Smoke / Validation ALL PASS plus WAIT / BLOCKED visual confirmation. User-localhost confirmation remains required before Completed / Specification Frozen.


### Runtime Schema visibility
The #048 test page shall render the Table Property definition from the Runtime-owned `BoneTable.getPropertySchema()` API. The HTML test page must not own a separate handwritten copy of the Table schema.

## tableStyle
Runtime-owned Property。default: `standard`。9 Presetを提供し、個別表示Propertyの明示値を優先する。`borderless` はセル罫線を全て抑止する。


## #029 Voucher snap alignment (#048 v1.0.31)

For a `cellElement:{renderer:"029",snapToCell:true}`, #048 now owns full-height
cell alignment and the voucher's vertical line reach, even when neighboring
cells determine a taller Table row. The behavior is scoped to snapped #029
Table cells; neither `BoneNumberBox` nor non-snapped elements are modified.
The cell `td` exposes `data-cell-renderer="029"` for stable Table-owned styling.
