ObjectsGrid
Which table to use
For a table-like list that breaks down into cards on narrow screens, use ObjectsGrid. For a native HTML table that keeps its table layout at every width, use the Tables primitives.
This page shows the Visual Contract of ObjectsGrid, the responsive object list that ViewList and FieldSetTabularInline render their rows through. It also covers the grid's cell components: ObjectsGridTableHeader, ObjectsGridBodyCell, ObjectsGridCardCell, ObjectsGridBodyCellSkeleton, and ObjectsGridCardCellSkeleton. Components describes the rules every component page shares.
Layout switch
One ObjectsGrid renders the same rows and fields in two layouts: a table at or above its tableBreakpoint, and a grid of cards below it. The default breakpoint is lg.
- The switch follows the viewport width, so a grid in a narrow container still renders a table on a wide viewport.
- Breakpoint names come from utils/breakpoints.breakpointsVueda, from
2xstoinf. xsalways renders the table.infkeeps cards at any practical viewport width.- The grid emits
update:isTableon mount and on every switch, withtruefor the table layout.
ViewList passes its own tableBreakpoint to the grid. CRUD Views describes the list chrome around the grid.
Both layouts render div elements with ARIA table, row, and cell roles.
Table layout
- Surface: the root (ObjectsGrid.root) carries the card fill in both layouts. In table layout it also carries the radius and Hairline edge that close the last row. A wide table scrolls sideways inside the root.
- Embedded grids: an ancestor marked
data-flushremoves the root's radius and edge, so the parent draws the only frame.FieldSetTabularInlineworks this way.ViewListremoves them through its own ViewList.objectsGrid key, so its strips above and below frame the grid. - Header: header cells (ObjectsGrid.headerCell, with content from ObjectsGridTableHeader) show the field label and are display-only. Sorting uses the SortControl menu and the active sort chips outside the grid.
- Dividers: a hairline on each row's cells divides that row from the next one. The same hairline divides the header band from the first data row. The root edge closes the grid below the last row. ObjectsGrid.table fills the root.
- Row height: body cells (ObjectsGridBodyCell.root) set row height from the
densityprop:default,compact, orcondensed, each tighter than the last. A table cell treats that height as a minimum, so a row holding a chip or an avatar renders taller. - Numbers: the grid renders numbers with tabular figures. A field descriptor with
numeric: trueright-aligns its header and cells.
The demo forces table mode with tableBreakpoint="xs".
Card layout
Below tableBreakpoint, each row renders as a card.
- Card: the row (ObjectsGrid.bodyRow) carries the card fill, radius, and edge. It is the only edge in this layout; the root keeps its fill and drops its edge.
- Card grid: cards flow into more columns as the viewport widens (ObjectsGrid.bodyRowGroup). To set a different column count, override
bodyRowGroupwith a Theme Override or a theme patch. - Fields: inside a card, ObjectsGrid.cardContainer aligns the fields into a label column and a value column. The label comes from ObjectsGridCardCell.header and the value from ObjectsGridCardCell.value.
- Header band: each card labels its own fields, so the header row group is hidden.
The demo uses tableBreakpoint="inf" so the cards show at every practical viewport width. It also removes the three-column step with a theme override, because the demo sits in a column narrower than the viewport.
Row states
ObjectsGrid.bodyRow styles each row in both layouts. A row takes its state from a data-state attribute, which the rowAttrs function can set per row.
- Hover and press: the row takes an accent tint.
selected: a low primary tint and a primary rail on the leading edge, so a selected row stays distinct from a hovered one.marked-destroy: a destructive tint and a strikethrough on every field except theitem-action-barcolumn, so its undo control stays readable.FieldSetTabularInlinesets it on rows that the user marks for removal.
ObjectsGrid.rowActions provides classes for row controls that a consumer places in a cell. The container stays hidden at rest and shows when the pointer is over the row, the row holds focus, or the row is selected. Its action class styles compact icon buttons. Apply both classes in your cell content.
Loading and empty
When loading is true and the grid has no rows, it renders skeletonRows rows of skeleton cells, one per field. getSkeletonClassForField sizes each skeleton by field type, and a field descriptor's skeletonClass replaces that size. A grid that already has rows keeps them on screen while it loads.
When the grid has no rows and is not loading, it renders one empty-state row:
- Width: the row spans the full width in both layouts. In table layout its cell is a
tdwithcolspan(ObjectsGrid.emptyText); in card layout the row spans the card grid. - Default content: an icon and the
emptyTextprop as the title, laid out by ObjectsGrid.emptyContent. The icon comes from the Icon Registry entry forObjectsGrid, keyed by the variant. - Variants:
emptyVariantisempty,filtered,loading, orerror. It setsdata-varianton the content, and the theme spins the icon forloadingand colors it destructive forerror. - Custom content: the
emptyslot replaces the icon and title. It receivesvariant. - No row:
:empty-text="null"removes the empty-state row unless you pass anemptyslot. Inline grids embedded in forms use this.
Tabular inline editing
FieldSetTabularInline embeds an editable ObjectsGrid in its own fieldset. The fieldset draws the outer edge and the separator above help and validation messages, so it is the only frame around the grid. Below its breakpoint (lg by default), the rows switch to cards.
Field picker menus
The sort and filter add-menus (SortControl and FilterMenu) list their available fields with FieldPickerMenuList. The list has a capped height (FieldPickerMenuList.list). A list longer than the cap keeps its scrollbar visible before any hover or scroll; a shorter list fits its content with no scrollbar. The same list appears in the desktop popover and the mobile dialog.
Theme keys and class props
Theme keys change every grid:
- ObjectsGrid:
root,table,headerRowGroup,headerRow,headerCell,bodyRowGroup,bodyRow,cardContainer,emptyText,emptyContent, androwActions(rootandaction). - ObjectsGridTableHeader:
rootandlabel. - ObjectsGridBodyCell:
root, plus a nested WidgetLabel override for widget labels inside table cells. - ObjectsGridCardCell:
headerandvalue.
Class props change one grid, keyed by field name: fieldClasses, tableFieldClasses, and cardFieldClasses style cells; headerClasses, tableHeaderClasses, and cardHeaderClasses style labels. The unprefixed prop applies in both layouts; the table and card props apply in one. Use them to tune a numeric column, an action column's width, or a compact field in one grid.