Found while implementing objectui#8474 (the shared hasCellValue calling [] a value). Filed unassigned, not claimed. Out of that card's fence: objectui#8474 fixes the record page's upstream predicate in @object-ui/plugin-detail; this is the defect in the cell renderer itself, in @object-ui/fields, on every other surface.
DOM shapes below are spelled out in words rather than written literally — tag-shaped fragments are eaten from GitHub bodies even inside backticks (AGENTS.md, "六种已实测的改写" ①).
What
SelectCellRenderer (packages/fields/src/index.tsx, the renderer registered for select, status, multiselect, radio, checkboxes and tags) opens with:
if (value == null || value === '') return <EmptyValue />;
[] passes that guard. Execution then reaches the array branch:
if (Array.isArray(value)) {
return (
<div className={cn('flex flex-wrap', appearance === 'dot' ? 'gap-x-3 gap-y-1' : 'gap-1')}>
{value.map((val, idx) => renderOne(val, idx))}
</div>
);
}
…which maps over zero entries. The renderer's whole output for [] is a childless flex-wrap DIV — measured directly on main at c90395b20, rendering the renderer on its own:
SelectCellRenderer([]) html: DIV with class "flex flex-wrap gap-1" and no children
No EmptyValue, no em-dash, no aria-label. A visually blank cell — and unlike the plugin-detail case, this one is inside the shared renderer, so it is the same blank cell on every surface that uses it.
Why objectui#8474 does not close this
objectui#8474 narrows hasCellValue so the record page never hands [] to a cell renderer at all — the row takes the placeholder branch upstream. RelatedList has its own isValueEmpty doing the same job for its grid (objectui#8459 / PR #8476). Both are upstream pre-checks in @object-ui/plugin-detail. The renderer they protect is still wrong, and every consumer that does not pre-check reaches it directly.
ObjectGrid is one such consumer, verified on c90395b20: packages/plugin-grid/src/ObjectGrid.tsx resolves a renderer through getCellRenderer(...) and calls it with the raw value (lines 2478, 2496, 2534, 2677, 2701) with no emptiness test in between. Its one EmptyValue fallback (line ~2537) is the no-renderer default path only, and its guard is value != null && value !== '' — the same hole, one branch over. So a multiselect column holding [] in an ObjectGrid paints a blank cell today.
Other registered consumers of getCellRenderer worth checking in the same sweep: packages/plugin-list (ObjectGallery), packages/plugin-kanban (ObjectKanban), packages/plugin-tree (ObjectTree), packages/plugin-dashboard (ObjectDataTable, DatasetWidget). Neither ObjectGallery nor ObjectKanban mentions EmptyValue or any local emptiness predicate at all (grep, c90395b20).
Shape of a fix (not settled — this is a finding, not a plan)
The narrow version is one clause in SelectCellRenderer: treat an array with zero entries the same as null. That is the same one-case widening objectui#8474 applied one layer up, and it is where it belongs — a renderer that has nothing to draw should say so itself rather than depend on every caller remembering to ask first.
A wider version would look at the other renderers' opening guards, several of which are spelled value == null || value === '' and share the blindness (JsonCellRenderer is the interesting counter-example: it draws the literal two-character text for [] and for the empty object, so it is not blank and should probably be left alone — objectui#8474 measured that).
Whatever the shape: the pin has to assert the rendered outcome, and it needs a non-regression axis that stays green for a populated array, otherwise a renderer that draws the placeholder for every array would pass.
Dedup
Searched objectstack-ai/objectui via MCP search_issues (REST is 403 from the dev container). Query 1 — the blank-cell-for-empty-array wording — returned objectui#8474 and objectui#8475 as control hits, so the channel is live in this session. Query 2, scoped to the @object-ui/fields guard wording, returned zero. Nothing covers the renderer-level hole: objectui#8474 is the plugin-detail predicate, objectui#8459 is RelatedList, objectui#8475 is RelatedList's hand-rolled em-dash.
Filed by an ObjectUI dev agent working objectui#8474, session session_01YBWFb5YgMU5dw8p2VKj16S, from branch claude/issue-8474-hascellvalue-empty-array. (Attribution written as prose deliberately: a footer block is stripped from issue bodies on create.)
Found while implementing objectui#8474 (the shared
hasCellValuecalling[]a value). Filed unassigned, not claimed. Out of that card's fence: objectui#8474 fixes the record page's upstream predicate in@object-ui/plugin-detail; this is the defect in the cell renderer itself, in@object-ui/fields, on every other surface.DOM shapes below are spelled out in words rather than written literally — tag-shaped fragments are eaten from GitHub bodies even inside backticks (AGENTS.md, "六种已实测的改写" ①).
What
SelectCellRenderer(packages/fields/src/index.tsx, the renderer registered forselect,status,multiselect,radio,checkboxesandtags) opens with:[]passes that guard. Execution then reaches the array branch:…which maps over zero entries. The renderer's whole output for
[]is a childless flex-wrap DIV — measured directly onmainatc90395b20, rendering the renderer on its own:No
EmptyValue, no em-dash, noaria-label. A visually blank cell — and unlike the plugin-detail case, this one is inside the shared renderer, so it is the same blank cell on every surface that uses it.Why objectui#8474 does not close this
objectui#8474 narrows
hasCellValueso the record page never hands[]to a cell renderer at all — the row takes the placeholder branch upstream.RelatedListhas its ownisValueEmptydoing the same job for its grid (objectui#8459 / PR #8476). Both are upstream pre-checks in@object-ui/plugin-detail. The renderer they protect is still wrong, and every consumer that does not pre-check reaches it directly.ObjectGridis one such consumer, verified onc90395b20:packages/plugin-grid/src/ObjectGrid.tsxresolves a renderer throughgetCellRenderer(...)and calls it with the raw value (lines 2478, 2496, 2534, 2677, 2701) with no emptiness test in between. Its oneEmptyValuefallback (line ~2537) is the no-renderer default path only, and its guard isvalue != null && value !== ''— the same hole, one branch over. So amultiselectcolumn holding[]in anObjectGridpaints a blank cell today.Other registered consumers of
getCellRendererworth checking in the same sweep:packages/plugin-list(ObjectGallery),packages/plugin-kanban(ObjectKanban),packages/plugin-tree(ObjectTree),packages/plugin-dashboard(ObjectDataTable,DatasetWidget). NeitherObjectGallerynorObjectKanbanmentionsEmptyValueor any local emptiness predicate at all (grep,c90395b20).Shape of a fix (not settled — this is a finding, not a plan)
The narrow version is one clause in
SelectCellRenderer: treat an array with zero entries the same asnull. That is the same one-case widening objectui#8474 applied one layer up, and it is where it belongs — a renderer that has nothing to draw should say so itself rather than depend on every caller remembering to ask first.A wider version would look at the other renderers' opening guards, several of which are spelled
value == null || value === ''and share the blindness (JsonCellRendereris the interesting counter-example: it draws the literal two-character text for[]and for the empty object, so it is not blank and should probably be left alone — objectui#8474 measured that).Whatever the shape: the pin has to assert the rendered outcome, and it needs a non-regression axis that stays green for a populated array, otherwise a renderer that draws the placeholder for every array would pass.
Dedup
Searched
objectstack-ai/objectuivia MCPsearch_issues(REST is 403 from the dev container). Query 1 — the blank-cell-for-empty-array wording — returned objectui#8474 and objectui#8475 as control hits, so the channel is live in this session. Query 2, scoped to the@object-ui/fieldsguard wording, returned zero. Nothing covers the renderer-level hole: objectui#8474 is the plugin-detail predicate, objectui#8459 isRelatedList, objectui#8475 isRelatedList's hand-rolled em-dash.Filed by an ObjectUI dev agent working objectui#8474, session
session_01YBWFb5YgMU5dw8p2VKj16S, from branchclaude/issue-8474-hascellvalue-empty-array. (Attribution written as prose deliberately: a footer block is stripped from issue bodies on create.)