Core API reference¶
- Composable
Table<T, C>: renders header and virtualized rows for read-only tables (tableData = Unit).- Required:
itemsCount,itemAt(index),state: TableState<C>,columns: List<ColumnSpec<T, C, Unit>>. - Slots:
placeholderRow(). - UX:
onRowClick,onRowLongClick,onRowMove,rowBlocks(supersedesonRowMove— see Row blocks below),contextMenu(item, pos, dismiss). - Look:
customization,colors = TableDefaults.colors(),icons = TableHeaderDefaults.icons()(defaults from the publicTableIconsset — see the Custom header icons guide),strings,shape,border(outer border;null= theme default,TableDefaults.NoBorder= no border). - Scroll: optional
verticalState,horizontalState. - Row identity:
rowKey(item, index)keys a row; it defaults to the row's position, and the table resolves no row to key one by position.rowKeyAt(index)is an optional key-by-index lookup that supersedesrowKeywherever a key is needed and must answer the same key — pass it when resolving a row has a side effect the table should not trigger for a key. A lazy list asks for keys over a range far wider than the viewport (130 rows from the top of the list), so a source that loads on access — a pager — reads keying throughitemAtas a viewport many times the real one. - Embedded content:
embeddedflag androwEmbeddedslot let you render nested detail content or even a secondary table inside each row, while still reusing the same table state, filters and formatting rules.
- Required:
- Composable
Table<T, C, E>: overload that accepts custom table data for headers, footers, and edit cells.- Additional parameter:
tableData: E- shared state accessible in headers, footers, custom filters, and edit cells. - All other parameters same as read-only variant.
- Additional parameter:
- Composable
EditableTable<T, C, E>: renders header and virtualized rows with editing support.- Additional parameters:
tableData: E,onRowMove,rowBlocks,onRowEditStart,onRowEditComplete,onEditCancel. - Columns must use
ColumnSpec<T, C, E>withEmatching the tableData type.
- Additional parameters:
- Columns DSL:
tableColumns<T, C, E> { ... }producesList<ColumnSpec<T, C, E>>for read-only tables.editableTableColumns<T, C, E> { ... }producesList<ColumnSpec<T, C, E>>for editable tables.- Column configuration:
- Cell:
cell { item, tableData -> ... }for regular cell content with access to table data (use_if table data is not needed). Cell content usescontext(TableCellScope), enabling helpers such asModifier.draggableHandle()andModifier.longPressDraggableHandle(). - Header:
header("Text")orheader(tableData) { ... }; optionaltitle { "Name" }for active filter chips. - Footer:
footer(tableData) { ... }for custom footer cell content with access to table data. - Editing:
editCell { item, tableData, onComplete -> ... }for custom edit UI. - Sorting:
sortable(),headerClickToSort(Boolean). - Filters UI:
filter(TableFilterType.*). - Sizing:
width(min, pref),autoWidth(max),resizable(Boolean),align(Alignment.Horizontal). - Row height hints:
rowHeight(min, max)used whenrowHeightMode = Dynamic. - Decorations:
headerDecorations(Boolean)to hide built‑ins when fully customizing header.
- Cell:
- Header customization
- When
headerDecorations = true(default), the table places sort and filter icons automatically. - For a fully custom header, set
headerDecorations(false)and use helpers insideheader { ... }:
- When
column(PersonField.Name, valueOf = { it.name }) {
headerDecorations(false)
header {
Row(verticalAlignment = Alignment.CenterVertically) {
Text("Name", modifier = Modifier.padding(end = 8.dp))
TableHeaderSortIcon()
TableHeaderFilterIcon()
}
}
sortable()
filter(TableFilterType.TextTableFilter())
}
- State:
rememberTableState(columns, initialSort?, initialOrder?, initialWidths?, settings?, dimensions?).- Compatibility normalization: when
settings.rowReorderEnabled = true,initialSortis ignored andstate.setSort()is a warning no-op — under an active sort a reorder would be unobservable, so the two features cannot both apply. - Sorting:
state.setSort(column, order?); currentstate.sort. - Grouping:
state.groupBy(column)to enable grouping;state.groupBy(null)to disable. - Column layout, selection and editing live in holders of their own —
state.columns,state.selectionandstate.editing. The members they took over in 2.1.0 are still onstateitself, deprecated, each naming its replacement; they are removed in the next major. Full mapping in the 2.0 migration guide. - Column order/size:
state.columns.setOrder(order),state.columns.resize(column, Set/Reset),state.columns.setWidths(map); currentstate.columns.orderandstate.columns.widths. - Auto-width recalculation:
state.columns.recalculateAutoWidths()to manually recompute column widths based on current content measurements. Useful for deferred/paginated data loading where initial auto-width calculation happened on empty data. - Filters:
state.setFilter(column, TableFilterState(...)); current per‑columnstate.filters. - Selection:
state.selection.toggleRow(index),state.selection.toggleCheck(index),state.selection.toggleCheckAll(count),state.selection.selectCell(row, column); currentstate.selection.selectedIndex,state.selection.checkedIndices,state.selection.selectedCell. - Editing:
state.editing.start(item, rowIndex, column),state.editing.tryComplete(),state.editing.cancel(); currentstate.editing.rowIndexandstate.editing.column.
- Compatibility normalization: when
- Settings and geometry
TableSettings:rowReorderEnabled,autoApplyFilters,autoFilterDebounce,stripedRows,showActiveFiltersHeader,selectionMode: None/Single/Multiple,groupContentAlignment,rowHeightMode: Fixed/Dynamic,enableDragToScroll(controls whether drag-to-scroll is enabled; when disabled, traditional scrollbars are used instead),editingEnabled(master switch for cell editing mode),showFooter( enable footer row display),footerPinned(pin footer at bottom or scroll with content),enableTextSelection(wrap table body inSelectionContainerto allow text selection; defaults tofalse),showVerticalDividers(show/hide vertical dividers between columns; defaults totrue),showRowDividers(show/hide horizontal dividers between rows; defaults totrue),showHeaderDivider(show/hide horizontal divider below header; defaults totrue),showFastFiltersDivider(show/hide horizontal divider below fast filters row; defaults totrue).- Row reorder mode notes: while
rowReorderEnabled = true, sorting and grouping UI is disabled. Filtering stays available; fast filters and active filters header continue to work. WithrowBlocks, note that dragging a partially hidden block still relocates the whole block in the source list — hidden members travel with it when the move is applied viaapplyRowBlockMove— see Row blocks. TableDimensions:defaultColumnWidth,defaultRowHeight,footerHeight,checkBoxColumnWidth,verticalDividerThickness,verticalDividerPaddingHorizontal,rowBlockSpacing.TableColors: viaTableDefaults.colors(...).
- Row blocks:
rowBlocks = RowBlocks(blockOf, onCommit, blockHeader, onRowReorderWithinBlock)makes adjacent rows sharing a non-nullblockOfid render and drag as one unit — see Row blocks.- Declared by identity: the table derives block extents itself from the snapshot it renders; there are no
index ranges to maintain. Hold the
RowBlocksinremember(identity equality); a stablerowKeyis required (the default positional key triggers a warning). onCommit(move: RowBlockMove): one event per completed whole-block drag, expressed in stable row keys (blockId,movedKeys,afterKey,beforeKey);nulldisables whole-block drag (standalone rows do not drag either). Apply the event to an in-memory list withMutableList<T>.applyRowBlockMove(move, keyOf, blockOf)— it relocates the whole block, hidden members included, and never splits another block.onRowReorderWithinBlock(move: RowWithinBlockMove): one event per within-block row reorder (blockId,movedKey,afterKey,beforeKey); every row carries a handle and reorders only within its block.nulldisables within-block reorder. Apply withMutableList<T>.applyRowReorderWithinBlock(move, keyOf, blockOf).- Supersedes
onRowMove: whilerowBlocksis passed, every whole-block/unit gesture reports throughonCommit(a standalone move carriesblockId == null), andonRowMoveis never invoked. blockHeader(blockId, rows): optional band content above the block, pinned to the viewport. It runs in aRowBlockHeaderScope, so aModifier.draggableHandle()there is the whole-block drag handle — a block needs one to be draggable as a whole.- Ordering helpers over consumer data:
List<T>.sortedWithinRowBlocks(blockOf, comparator)(blocks never fragment) andList<T>.filteredWholeRowBlocks(blockOf, predicate)(a block survives whole when any member matches). - Suppressed while
groupByis active (warning logged; row drag is disabled entirely —onCommitis not invoked andonRowMovestays superseded); the read-only flagTableState.rowBlocksSuppressedByGroupBysurfaces the conflict, and the column menu's group-by item is disabled while blocks are present. - A cell
Modifier.draggableHandle()reorders a block row within its block (or a standalone row among units);TableRowContext.isInRowBlockletsTableCustomizationstyle block members;TableColors.rowBlockContainerColortints the band.
- Declared by identity: the table derives block extents itself from the snapshot it renders; there are no
index ranges to maintain. Hold the
For the full generated API, see the API Reference.