Table
Display rows of data in columns.
1use herogpui::components::table::Table;Usage
Headers use 12px text with 16px lines; cells use 14px text with 20px lines in both ordinary and virtual rows.
1use herogpui::prelude::Table;
2use gpui::prelude::*;
3
4stretch_col(vec![build("tbl-usage").into_any_element()])Live HeroGPUI compiled to WebAssembly. Select any example without loading another WASM instance.
Anatomy
Rust types
TableTableColumnTableRow
Table is assembled from these builders. The API reference lists each one.
Customization
Appearance builders and theme tokens Table uses.
Styling
| Style | Description |
|---|---|
w_full + overflow_hidden | Is a full-width overflow-hidden flex tray, not a CSS grid with minmax(0,1fr) tracks. |
surface_secondary + px/pb(px(4.)) + radius_lg * 2.5 min 32 | Gray tray inset and overlay-sized radius around the surface card. |
variant Secondary skips the tray | Secondary leaves the root flat; first/last header rounding and per-cell hover fills are not reproduced. |
overflow_x_scroll | Horizontal input scrolls the content column; vertical input is not remapped sideways. Custom scrollbar styling is absent. |
min_w_full flex_col text_size(px(14.)) line_height(px(20.)) | 14px type and 20px line height match; is a flex column rather than a border-separate table, so column tracks resolve per row and a table narrower than its columns times their widest cell staggers the body against the header. |
border_b_1 + separator.alpha(0.5) + surface_secondary | Header rule and secondary fill on primary; the separator is rendered at 50% alpha. |
px(16.) py(10.) text_size(12.) line_height(16.) MEDIUM + label.clone() | 16/10px inset and 12px type with 16px lines match; uses medium caller-case labels, but short vertical column separators are not drawn. |
flex items_center gap(px(4.)) | Label and indicator share the header cell with a 4px gap rather than space-between. |
svg size(px(12.)) + CHEVRON_UP/DOWN | 12px chevron matches; ascending/descending are separate glyphs rather than a 100ms rotate. |
radius_2xl.min(px(32.)) + overflow_hidden on primary | Primary clips the body to radius_2xl; secondary does not undo per-cell rounding because those cell radii are not drawn. |
border_b_1 + separator.alpha(0.5) except final visible row | Rows use the separator at 50% alpha, and the final visible row omits the bottom border. |
px(16.) py(12.) | 16/12px inset matches; cell fill lives on the primary body, not on each cell, and hover/selected paints the row. |
pl(px(12. + 20. * depth)) | Indents 16px per 1-based level; uses 12 + 20 * depth and only when depth > 0. |
flex items_center px(16.) py(10.) | Footer inset matches. |
h(16.) w(1.) hairline_radius + group_hover/is_resizing + right(-8.) | Resting line, hover/drag bar and 8px grab margin match; touch-none is implicit in mouse/key handling. |
allows_resizing handle + overflow_x_scroll | No separate overflow-auto host; column handles live in the header and the x-scroller is ScrollContainer. |
gap(px(8.)) py(px(8.)) | 8px gap and padding around the built-in spinner. |
inset_focus_ring on the focused row | One overlay ring is painted on the row instead of three-sided per-cell shadows. |
API reference
Builders
| Builder | Type | Default | Description |
|---|---|---|---|
variant( | TableVariant | TableVariant:: | Primary draws the gray tray and surface card; secondary is flat. |
new( | columns | — | Compound ScrollContainer, Content, Footer and related parts; takes columns up front and builders for the rest. |
selection_mode( | SelectionMode | SelectionMode:: | Adds the selection column and row-activation behaviour when not none. |
selected_keys( | Selection | — | Controlled selected keys as shared strings rather than RAC's Set/"all" union. |
on_selection_change( | Fn( | — | Reports the whole selection after a row, checkbox or select-all change. |
sort_descriptor( | descriptor | — | Current sort column and direction, shown in the header. The table does not reorder its own rows. |
on_sort_change( | Fn( | — | Sortable header activation; the caller rebuilds rows from the descriptor. |
disabled_keys( | iterable of keys | — | Pinned RAC inherited keys excluded from selection, actions and the roving tab stops. |
on_row_click( | Fn( | — | Pinned RAC row action; reports the visible row index rather than the collection key. |
expanded_keys( | iterable of keys | — | Controlled parent keys whose nested rows are shown. |
on_expanded_change( | Fn( | — | Reports the expanded set after a tree chevron is pressed. |
tree_column( | index | — | Column that carries the expand chevron and indent; takes a column index rather than a column key. |
columns( | columns | — | Dynamic column data for the render-prop pattern; takes configured TableColumn values. |
column( | column | — | Static columns or a render prop; appends configured columns. |
new( | label | — | Column identifier; keys sorting and labels by the constructor text rather than a separate id. |
allows_sorting( | bool | false | Makes the header a sort control. |
is_row_header( | bool | false | Marks the identifying column; without an accessibility tree the effect is medium-weight cell text. |
default_width( | width | — | Starting width for a resizable column. CSS length strings are not accepted; takes pixels. |
min_width( | width | 75 | Pinned RAC resize floor; also applies this 75px default when resizing. |
max_width( | width | — | Pinned RAC inherited ceiling for a resizable column. |
allows_resizing( | bool | false | Pinned RAC inherited flag that draws a drag handle on the column's trailing edge. |
width( | width | — | Caller-owned controlled width in pixels; CSS length and fractional strings are not accepted. |
row( | cells | — | Dynamic row data; static rows are appended one at a time and virtual tables take a factory instead of a generic item list. |
empty_state( | content | — | Content shown when there are no rows; takes an element rather than a render-prop that receives TableBodyRenderProps. |
key( | key | — | Row identifier used for selection; numeric RAC keys are represented as shared strings, defaulting to the row index. |
new( | cells | — | Row cells; takes opaque elements rather than Table.Cell parts, so cell-level RAC props are not independently addressable. |
text_value( | string | — | Pinned RAC typeahead string; cells are opaque, so rows without this value do not participate. |
children( | rows | — | Whether nested rows exist, even if not loaded; infers this from nested TableRow children. |
indicator( | "ascending" | | — | Current direction, handed to the sort-indicator closure rather than accepted as a header child prop. |
show_indicator( | bool | true | Whether a sorted column draws its direction chevron. |
footer( | content | — | Footer content such as pagination. |
on_resize_start( | Fn( | — | Reports known pixel widths when pointer or keyboard resizing begins. |
on_resize( | Fn( | — | Reports each proposed pixel width map; feed values back through controlled TableColumn.width. |
on_resize_end( | Fn( | — | Reports the final known pixel widths after pointer or keyboard resizing ends. |
is_pending( | bool | false | Shows the load-more sentinel content; spells the loading flag as is_pending. |
on_load_more( | Fn( | — | Called when the sentinel intersects the scroll viewport. |
scroll_offset( | offset | 1 | Pinned RAC inherited viewport-height margin before the sentinel counts as visible. |
virtual_rows( | count, | — | RAC Collection items for mixing static and dynamic cells; the port's analogue is the virtual row factory, not a cell-level collection mixer. |
row_height( | height | 48 | Fixed virtual row height; with virtual_rows this selects gpui uniform_list, caps at max_h, shrinks below it in a bounded parent, and pages by the visible viewport while skipping disabled stops. |
estimated_row_height( | height | — | Estimated height for variable virtual rows; selects gpui list instead of uniform_list. |
loader_height( | height | 48 | Fixed height of the load-more row. |
gap( | gap | 0 | Space between rows; leaves this at 0. |
padding( | padding | 0 | Padding around the list; leaves this at 0. |
Parts
| Part | Description |
|---|---|
Table | Root tray that owns variant, selection, sort, virtualization and load-more state. |
Table | Horizontal overflow wrapper around the content column so a wide table can scroll without stretching the footer. |
Table | Flex column standing in for the table; border-separate table layout is not reproduced. |
Table | Header row of column cells, including the optional select-all checkbox. |
TableColumn | Configured header cell with sort, resize and row-header flags. |
Table | Row list, empty state and the primary-variant surface card. |
TableRow | One body row with optional nested children, selection key and typeahead text. |
TableRow | Data cells are opaque elements inside TableRow; there is no Cell part to compose or span. |
Table | Sortable header wrapper and direction indicator drawn when allowsSorting is set. |
Table | Optional row under the body, where places pagination. |
TableColumn | Trailing-edge resize handle drawn when allowsResizing is set; not a separately constructed child. |
Table | V3's overflow-auto resize host is not a separate wrapper; resizing hangs off columns and horizontal scroll stays on ScrollContainer. |
Table | Intersection sentinel that fires onLoadMore, including virtual end-of-list detection. |
Table | Built-in spinner and Loading… label; caller children cannot replace that content. |
Table | RAC mixer for static plus dynamic cells; exposes whole-row factories instead. |
States
| Builder | State | Description |
|---|---|---|
row.hover(default.soft) | Hovered | Tints cells with bg-surface/40 (secondary: bg-default/50); paints default.soft on the whole interactive row. |
row.bg(accent.soft) | Selected | Uses bg-surface/10 on cells; fills the row with accent.soft so selection still reads when the checkbox is off-screen. |
inset_focus_ring | Focus visible | Inset focus ring on the focused row, column header and resizer; one overlay stands in for v3's per-cell split ring. PageUp enters the first header — from the top of a virtual body, paging by viewport mid-body; Down and PageDown return to the first and last enabled body rows. |
disabled_keys + disabled_opacity | Disabled row | DisabledKeys rows are dimmed and removed from selection, actions and keyboard stops. |
allows_sorting + cursor_pointer + sort_focus | Sortable | Sortable headers use the interactive cursor, hover fill and keyboard activation. |
is_resizing / group_hover / resize_focused | Resizing | The handle grows to a full-height accent (or focus) bar while dragged, hovered or keyboard-resizing. |
empty_state | Empty | Caller empty-state content is centered in the body when there are no rows. |
is_pending + on_load_more | Loading | Pending sentinel shows the built-in spinner while onLoadMore can still fire from intersection. |