ArenaTableCell.prompt.md
September 6, 2026 ยท View on GitHub
One cell of an ArenaTableRow. The cell draws the cell box: the padding, the alignment and the mono or gold treatment its column asks for. In card mode it draws either a label and value pair or a full-width block. The cell shows whatever you put in it.
<ArenaTableCell>{d.p95}</ArenaTableCell>
<ArenaTableCell><ArenaBadge tone="danger" dot>Failed</ArenaBadge></ArenaTableCell>
<ArenaTableCell><ArenaButton variant="ghost" size="sm">Details</ArenaButton></ArenaTableCell>
Members, in contract order and under this layer's own names. * marks a required one.
Do / Don't
- Put a value in it, or one of Arena's own components: an
ArenaBadgefor a status, anArenaButtonfor an action. This member is whyArenaTableis a compound component at all. A column-levelrenderfunction would be per-item projection, which the library does not do. A cell you instantiate is just an element you wrote. - Don't set alignment, width or the mono face here. Those belong to the column, so a column stays consistent down its whole length. A cell that styled itself would drift from its header.
- Don't add a
roleor atabIndex.role="gridcell"and the roving tab stop belong to the enclosingArenaTable's grid, and both are injected. Adding your own would put a second tab stop inside a composite that must have one. - A control you put in a cell is a page-level tab stop, and that is deliberate. Arena cannot silence markup it does not own, and silencing it would take away a route a keyboard user has. Reaching it must cost exactly one Tab; step 2 of "Verifying the grid by hand" in
ArenaTable.prompt.mdis the standing check. - Don't use it outside an
ArenaTableRow. The cell renders. With no column it has no alignment, no header to pair with in card mode, and no place in the keyboard order.
href makes the cell a real destination, and the row keeps its own
href draws an <a> around the cell's content, inside the cell box. The cell is the one place HTML admits it. An anchor around the whole row would break the row and cell structure the grid is made of. An anchor may not contain the ArenaButton a cell's own contract invites into it.
<ArenaTableCell href={`/sales/${sale.id}`} onNavigate={() => navigate(`/sales/${sale.id}`)}>
{sale.number}
</ArenaTableCell>
The member carries the anchor convention the four members before it carry, without restating it. A primary click with no modifier is cancelled and reported through onNavigate, so your router owns it. Ctrl, meta, shift, alt, a middle click and a context menu stay the browser's and report nothing at all. The reader asked for a new tab or for the address.
Inside a row carrying interactive, the anchor wins and the row does not fire. The behaviour is not a special case written for this member. The behaviour is the rule the row already applies to a checkbox or a button you put in a cell. A press landing on a control inside the row was never the row's. So a
table can have a link in its first column and a clickable row under it, and one press runs one
destination. A cell with no href in the same row still activates it.
The anchor is a tab stop of its own, one Tab from the cell rather than a step-in the grid does not have. A tab stop of its own is the answer this table already gives for any control you draw in a cell. The
grid's Enter is the cell's and still activates the row; the anchor's Enter is the anchor's.
What is injected, and therefore not yours
column, layout, tabIndex, focused and onCellFocus arrive from ArenaTableRow (fed by ArenaTable) through cloneElement. None of them is part of this component's API, none is in contracts/api/components/ArenaTableCell.json, and a consumer never writes one. ArenaRadioGroup injects name, checked and onSelect into each ArenaRadio in the same shape.
The rules of the language hold in the code you write from this page. An Arena component is not a styling surface, so put no className of your own on it. Read every value through its token, never a raw colour and never a bare 16px. Never wrap it in your router's own link. arena-to-prod --audit reports these three in your sources. The rest are in ../../../../../skills/design/SKILL.md, which marks the ones it reports.