Skip to content

Migrating from 2.x to 3.0

3.0.0 collects the accessibility, keyboard, right-to-left and visual work done after 2.4.1, and removes what 2.x deprecated. Everything that changed is listed here, in the order you are likely to hit it. The compiler flags source changes; it does not flag the new visual defaults in the last section, resource packaging on iOS and web, or libraries compiled against 2.x.

Icons are Compose resources

The library ships its icons as Compose resource files instead of ImageVector code, so it carries no icon dependency of its own.

  • TableIcons values are DrawableResource; draw one with painterResource.
  • TableHeaderIcons and TableHeaderDefaults.icons(...) take Painter instead of ImageVector.
  • LocalTableHeaderIcons has no default outside a Table: a resource painter exists only inside composition. Reading it outside a Table throws.
Before
val icons = TableHeaderDefaults.icons(
    sortAsc = Icons.Default.KeyboardArrowUp,
    filterActive = TableIcons.FilterAltFilled,
)
After
val icons = TableHeaderDefaults.icons(
    sortAsc = rememberVectorPainter(Icons.Default.KeyboardArrowUp),
    filterActive = painterResource(TableIcons.FilterAltFilled),
)

Android and desktop apps get the icon files inside the library's aar and jar. iOS and web apps get them through Compose Multiplatform resources packaging, which the org.jetbrains.compose Gradle plugin sets up; a build that skips it, such as a hand-made XCFramework, fails when a Table renders. See Custom header icons.

No more ExperimentalTableApi

The marker has been deprecated since 2.0.0 and is now gone; a leftover opt-in fails with Unresolved reference: ExperimentalTableApi. Delete every opt-in:

Before
@OptIn(ExperimentalTableApi::class)
@Composable
fun PeopleTable(items: List<Person>) { /* ... */ }
After
@Composable
fun PeopleTable(items: List<Person>) { /* ... */ }

TableState forwarders are gone

In 2.1.0 column, selection and editing state moved to state.columns, state.selection and state.editing, and the old members on TableState stayed as deprecated forwarders. They are removed. If you still have warnings from 2.x, apply the IDE's Replace with quick fix before upgrading; otherwise use this table.

Removed Use instead
columnOrder columns.order
columnWidths columns.widths
columnContentMaxWidths columns.contentMaxWidths
columnHeaderWidths columns.headerWidths
autoWidthAppliedForEmpty columns.autoWidthAppliedForEmpty
autoWidthAppliedForData columns.autoWidthAppliedForData
resolveColumnWidth(key, spec) columns.resolveWidth(key, spec)
moveColumn(fromIndex, toIndex) columns.move(fromIndex, toIndex)
setColumnOrder(newOrder) columns.setOrder(newOrder)
resizeColumn(column, action) columns.resize(column, action)
setColumnWidths(widths) columns.setWidths(widths)
updateMaxContentWidth(column, width, source) columns.updateMaxContentWidth(column, width, source)
setColumnWidthToMaxContent(column) columns.fitToContent(column)
recalculateAutoWidths() columns.recalculateAutoWidths()
selectedIndex selection.selectedIndex
checkedIndices selection.checkedIndices
selectedCell selection.selectedCell
toggleSelect(index) selection.toggleRow(index)
focusRow(index) selection.focusRow(index)
toggleCheck(index) selection.toggleCheck(index)
toggleCheckAll(count) selection.toggleCheckAll(count)
selectCell(rowIndex, column) selection.selectCell(rowIndex, column)
editingRow editing.rowIndex
editingColumn editing.column
onRowEditStart editing.onRowEditStart
onRowEditComplete editing.onRowEditComplete
onEditCancel editing.onEditCancel
startEditing(item, rowIndex, column) editing.start(item, rowIndex, column)
tryCompleteEditing() editing.tryComplete()
completeCurrentCellEdit(visibleColumns) editing.completeCurrentCell(visibleColumns)
cancelEditing() editing.cancel()

New UiString keys

Screen-reader names, the column menu, the empty states, filter labels and the format dialog add about ninety UiString keys (HeaderSort, ColumnMenuPinLeft, EmptyNoResults, FilterErrorInvalidNumber, FormatRuleSave, …). A custom StringProvider whose when has an else branch keeps compiling and shows that branch's text for the new keys. One with an exhaustive when and no else stops compiling until it covers them. To translate only some keys, fall back to the English defaults:

object UkStrings : StringProvider {
    @Composable
    override fun get(key: UiString): String =
        when (key) {
            UiString.FilterClear -> "Очистити"
            // ...
            else -> DefaultStrings.get(key)
        }
}

Deprecated in 3.0, removed in 4.0

These still compile, with a deprecation warning, and are removed in 4.0. The IDE quick fix applies where a direct replacement exists.

Deprecated Use instead
PinnedSide.Left PinnedSide.Start (the leading side, right in RTL)
PinnedSide.Right PinnedSide.End
TableActiveFilters without tableData pass tableData, so a chip click opens its filter panel
handleLoadState the paged Table's loadingContent, errorContent, emptyContent, loadingIndicator and errorBar

Recompile

Binary compatibility with 2.x is broken. Among others, new parameters change the JVM signatures of Table, EditableTable, the paged Table and TableDefaults.colors, and the constructors and copy of TableDimensions, TableSettings, TableColors and ColumnSpec; PinnedSide.Left and Right are no longer enum entries. A library compiled against 2.x fails at runtime with NoSuchMethodError or NoSuchFieldError until it is recompiled against 3.0.

New visual defaults

These compile unchanged but look different. Each comes from the theme, so a Material theme of your own carries through; to get the 2.x look back, pass the old value explicitly. Some have no switch.

Change Old look
Selected row is secondaryContainer with a leading indicator bar TableDefaults.colors(rowSelectedContainerColor = MaterialTheme.colorScheme.tertiary) and TableDefaults.standardDimensions().copy(selectionIndicatorWidth = 0.dp)
Striped rows are surfaceContainerLow TableDefaults.colors(stripedRowContainerColor = MaterialTheme.colorScheme.surfaceContainerLowest)
Header, body, footer and group rows have their own text styles Table(typography = TableDefaults.typography(header = LocalTextStyle.current, body = LocalTextStyle.current, footer = LocalTextStyle.current, groupHeader = LocalTextStyle.current)) (2.x used the ambient text style everywhere)
Headers follow the column's alignment headerAlign(Alignment.Center) on the column (2.x centered headers)
Row, header, footer, group and fast filter heights grow with the system font size TableDefaults.standardDimensions().copy(scaleWithFontSize = false)
Rows animate to their new place after a sort TableSettings(motion = TableMotion.Reduced) is the closest switch; it also turns off the column-move and drag-lift animations 2.x had
Icons are Material Rounded glyphs Header icons: your own painters in TableHeaderDefaults.icons(...); other icons have no switch
The sort icon of an unsorted column is dimmed No switch