All notable changes to this project will be documented in this file.
- Fixed: Header content state and tooltip behavior for truncated titles.
TruncationTooltipBoxnow accepts a composable title provider for better content flexibility.- Header content renders via
movableContentOfto prevent state loss on recomposition. - Updated tooltip position provider usage for consistent tooltip placement.
- Updated: Kotlin to 2.3.20.
- Kotlin version bumped from 2.3.10 to 2.3.20.
- Refactored: Compose dependencies migration to version catalog.
- Replaced direct Compose extension dependencies with
libs.versions.tomlaliases. - Aligned module usage across convention and sample Gradle scripts.
- Replaced direct Compose extension dependencies with
- Updated: Gradle wrapper to 9.4.0 version.
Compare: v1.8.1...v1.8.2
- Added: Improved mobile platform interactions for column headers.
- Column headers now have draggable handles enabled on mobile for reordering operations.
- Hover interactions are now disabled on mobile platforms to prevent touch gesture conflicts.
- Changed:
enableDragToScrollsetting now defaults to platform-aware value.- Default value changed from
truetogetPlatform().isMobile()- enabled on mobile, disabled on desktop. - Drag-to-scroll remains available on desktop when explicitly enabled in settings.
- Default value changed from
- Changed: Removed incompatible normalization between row reorder and drag-to-scroll.
rowReorderEnabledandenableDragToScrollcan now be enabled simultaneously.- Previously, enabling row reorder would force disable drag-to-scroll; this behavior has been removed.
- Updated: Sample app settings sidebar to reflect new interaction options.
- Drag to scroll and row reorder toggles are now independent controls.
Compare: v1.8.0...v1.8.1
- Added: Public row reordering API for table rows powered by Reorderable.
- Added
onRowMovecallback toTableandEditableTablefor handling row position changes. - Added
TableItemScopeandTableCellScopeto expose item-scoped drag helpers inside cell content. - Added
Modifier.draggableHandle()andModifier.longPressDraggableHandle()for building custom row drag handles directly incell { ... }. - Row reordering now works for both regular lazy tables and embedded table bodies.
- Added
- Changed: Table cell DSL now uses Kotlin context parameters.
ColumnSpec.celland thecell { ... }builder now run withcontext(TableCellScope).- Existing cell implementations usually continue to work unchanged, while advanced cell content can now access row-scoped helpers without extra parameters.
- Changed: Row reorder mode now normalizes incompatible interactions more explicitly.
TableSettings.rowReorderEnabledis now the primary setting name; deprecatedisDragEnabledremains supported for compatibility.- When row reorder mode is enabled,
enableDragToScrollis forced tofalseandinitialSortis ignored. - Sorting and grouping interactions are disabled while row reorder mode is active to avoid conflicting gestures and state.
- Fixed: Number filter source text formatting in
NumberFilterState.- Improves formatting consistency for number filter source values.
- Updated: Compose Multiplatform and related dependencies.
- Compose Multiplatform upgraded from
1.10.2to1.10.3. - AndroidX Lifecycle upgraded from
2.9.6to2.10.0.
- Compose Multiplatform upgraded from
Compare: v1.7.15...v1.8.0
- Fixed: Disabled SelectionContainer during row editing to prevent cross-hierarchy text selection issues.
- When text selection is enabled and a row is being edited, SelectionContainer is now disabled.
- Resolves issues with popup-based editors on Desktop targets where text selection could interfere with editing.
- Fixed: Prevent parent click activation on Space key in edit cell focus synchronization.
- Added key event handler to prevent Space key from being interpreted as click activation on parent elements.
- Improves keyboard navigation experience in editable tables.
- Updated: Compose Multiplatform upgraded to 1.10.2.
- AndroidX Activity Compose updated from 1.12.4 to 1.13.0.
- Kermit updated from 2.0.8 to 2.1.0.
- Paging for KMP updated from 2.2.6 to 2.2.7.
- Ktlint Gradle updated from 14.0.1 to 14.2.0.
Compare: v1.7.14...v1.7.15
- Fixed: Crash caused by ScrollState handling in dropdown menu.
- Removed scrollbar renderer from
FormatDropdownFieldand related components. - The scrollbar state management was causing crashes in certain scenarios.
- Format dialog now works reliably without custom scrollbar integration in dropdowns.
- Removed scrollbar renderer from
- Changed: Refactored FormatDialog data classes to separate files.
EditFormatRulemoved toua.wwind.table.format.datapackage with@Immutableannotation.FormatDialogSettingsmoved toua.wwind.table.format.datapackage with@Immutableannotation.- Improves code organization and stability for Compose.
- Changed: Added button in FormatDialog now uses FloatingActionButton instead of IconButton.
- Provides better visual prominence and Material 3 compliance.
- Close button now uses explicit close icon for clarity.
- Updated: Sample app import for
FormatDialogSettingsto use new package location.
Compare: v1.7.13...v1.7.14
- Added: Null-check filter support (IS_NULL / IS_NOT_NULL) for text, number, and date filters.
- Added
FilterConstraint.isNullCheck()extension function to identify null-checking constraints. - Added
TableFilterState.isActive()extension function to determine if a filter should be shown as active in the UI. - Filter UI now hides input fields when null constraint is selected (text, number filters).
- Previously, filters with null constraints would not display properly in active filter chips.
- Added
- Fixed: Active filter chips now correctly display null-check filters.
- Previously, filters with IS_NULL/IS_NOT_NULL constraints had empty values list and were not shown as active.
- Now these filters are properly recognized as active and displayed in the active filters row.
- Changed: Active filters row now uses scrollable LazyRow with navigation arrows.
- "Clear all" chip is now fixed on the left while filter chips can scroll horizontally.
- Left/right arrow buttons appear when filters overflow the available width.
- Improves usability when many filters are active simultaneously.
- Added: Date filter support in conditional formatting dialog.
- Full date filter UI with date picker, constraint selection, and range support.
- Supports IS_NULL and IS_NOT_NULL constraints for conditional formatting rules.
- Added: Vertical scrollbar support for formatting dialogs.
- New
VerticalScrollbarRendererandVerticalScrollbarStatefor custom scrollbar rendering. - Optional
scrollbarRendererparameter added toFormatDialogandFormatDialogConditionTab. - Enables proper scrollbar integration in desktop environments.
- New
- Changed: Updated Kotlin to 2.3.10 and Compose Multiplatform to 1.10.1.
- AndroidX Activity Compose updated from 1.12.2 to 1.12.4.
- Paging for KMP updated from 2.2.3 to 2.2.6.
- Liquid updated from 1.1.0 to 1.1.1.
- Kover (code coverage) updated from 0.9.4 to 0.9.7.
Compare: v1.7.12...v1.7.13
- Fixed: Prevent redundant scroll to top when sort state is unchanged.
- Added state tracking with
rememberSaveableto detect actual sort changes. - Previously, any
LaunchedEffectre-execution would trigger scroll to top, even when sort state remained the same. - Now, scroll to top only occurs when the sort state actually changes, improving user experience during recomposition.
- Added state tracking with
Compare: v1.7.11...v1.7.12
- Fixed: Header widths are now preserved during auto-width recalculation.
- Added
columnHeaderWidthsmap to store header measurements separately from row measurements. - When
recalculateAutoWidths()is called, header widths are retained and used as base values. - Previously, calling
recalculateAutoWidths()would clear all measurements including headers, causing columns to lose header-based sizing since headers only measure once on initial render.
- Added
Compare: v1.7.10...v1.7.11
Add debug logging for column auto-width measurement
- Add verbose-level logging to track auto-width calculation flow
- Log width updates with source identification (Header/Row[N])
- Log auto-width reset and recalculation triggers
- Log computed widths with measured/base/final values
- Log phase transitions (empty table / first data)
Tag: TableAutoWidth
Compare: v1.7.9...v1.7.10
- Fixed: trigger header width re-measurement when title text changes. Previously, headers with lazy-loaded content would only measure once with empty/initial text, causing incorrect column widths on double-click resize.
Compare: v1.7.8...v1.7.9
- Fixed: Fast Filters row now only displays when at least one visible column has a filter configured.
- Previously, the row would show even when no columns had filters, resulting in an empty filters row.
- Now requires both
showFastFilters = trueAND at least one visible column with a non-null, non-disabled filter. - Columns with
nullorDisabledTableFilterare excluded from the visibility check.
Compare: v1.7.7...v1.7.8
- Added: Configurable divider visibility settings in
TableSettings.showVerticalDividerscontrols vertical dividers between columns (default:true).showRowDividerscontrols horizontal dividers between rows (default:true).showHeaderDividercontrols horizontal divider below the header (default:true).showFastFiltersDividercontrols horizontal divider below the fast filters row (default:true).
- Added: Validation for
TableDimensionsdivider thickness values.dividerThicknessandpinnedColumnDividerThicknessmust be at least1.dp.- Invalid values now throw
IllegalArgumentExceptionwith descriptive message.
- Fixed: Pinned footer not visible when table body content is large.
- Changed footer rendering from sequential Column layout to overlay positioning using Box with
Alignment.BottomStart. - Added bottom padding to body content to prevent overlap with footer.
- Changed footer rendering from sequential Column layout to overlay positioning using Box with
- Changed: Refactored
EditableTableto reduce cyclomatic complexity.
Compare: v1.7.6...v1.7.7
- Added:
borderparameter toTableandEditableTablecomposables for customizable outer table border.- Accepts
BorderStroke?to fully customize border appearance (color, thickness, brush). null(default) applies theme-based border usingdividerThicknessandMaterialTheme.colorScheme.outlineVariant.TableDefaults.NoBordersentinel value disables the outer border entirely.- Paging
Tablefunctions updated with the sameborderparameter for API consistency.
- Accepts
Compare: v1.7.5...v1.7.6
- Added:
enableTextSelectionsetting inTableSettingsfor optional text selection support in table rows.- When enabled, wraps the table body in Compose
SelectionContainerto allow users to select and copy text content. - Defaults to
falseto preserve existing behavior and avoid interfering with row click/selection interactions. - Useful for data display tables where users need to copy cell values without custom clipboard handling.
- When enabled, wraps the table body in Compose
Compare: v1.7.4...v1.7.5
- Changed: Updated Kotlin to 2.3.0 and related tooling dependencies.
- Kotlin version bumped from 2.2.21 to 2.3.0.
- AndroidX Activity Compose updated from 1.12.0 to 1.12.2.
- Kover (code coverage) updated from 0.9.3 to 0.9.4.
- Compose Stability Analyzer updated from 0.6.0 to 0.6.6.
Compare: v1.7.3...v1.7.4
BREAKING CHANGES:
- Changed: Cell lambda signature updated to include
tableDataparameter for consistent API across all table components.ColumnSpec.cellsignature changed from@Composable BoxScope.(T) -> Unitto@Composable BoxScope.(T, E) -> Unit.- All cell content now receives the table data parameter, matching the signature of
header,footer, andeditCell. - Provides access to shared state within regular cell rendering, enabling dynamic behavior based on table-wide context.
- Migration: Update all
cell { item -> ... }declarations tocell { item, tableData -> ... }orcell { item, _ -> ... }if table data is not needed. - Example:
// Before (1.7.2) cell { item -> Text(item.name) } // After (1.7.3) cell { item, tableData -> // Can now access tableData for conditional rendering Text(item.name) } // Or use underscore if not needed cell { item, _ -> Text(item.name) }
Benefits of this change:
- Consistent lambda signatures across all table component slots (cell, header, footer, editCell).
- Cells can now access shared table state for dynamic rendering without prop drilling.
- Better alignment with the table data pattern introduced in v1.7.1.
- Enables more flexible cell customization based on table-wide context.
Compare: v1.7.2...v1.7.3
- Added:
shapeparameter to pagingTablecomposables for customizable table surface shape (default:RoundedCornerShape(4.dp)).- Aligns paging module API with core table module for consistent shape customization.
- Both overloads of paging
Tablefunction now support shape parameter.
- Added: New paging
Tablecomposable overload withtableDataparameter for shared state access.- Enables passing table data to headers, footers, and edit cells in paging tables.
- Generic parameter
Erepresents table data type, consistent with core table API. - Provides full feature parity with core
Tablecomposable for table data customization.
Compare: v1.7.1...v1.7.2
- Added: Support for custom table data (
tableDataparameter) that can be shared across headers, footers, filters, and edit cells.- New
Tableoverload that acceptstableDataparameter for passing shared state to table components. - Generic parameter
Enow represents table data type instead of edit state type for improved flexibility. - Headers, footers, and edit cells receive table data as a parameter, enabling access to shared state during rendering.
- Filters (custom, fast, and panel) receive table data for enhanced customization and state synchronization.
EditableTableparameter renamed fromeditStatetotableDatato better reflect its purpose.
- New
- Changed: Enhanced column specification API for table data support.
ColumnSpec.headersignature changed from@Composable () -> Unitto@Composable (E) -> Unit.ColumnSpec.footersignature changed from@Composable BoxScope.() -> Unitto@Composable BoxScope.(E) -> Unit.ColumnSpec.editCelldocumentation updated to clarify table data parameter usage.ReadonlyTableColumnsBuildernow generic over table data typeEfor consistent API surface.TableFilterType.Custominterface methods updated to receive table data parameter.
- Changed: Documentation improvements and sample app refactoring.
- README updated with comprehensive table data usage examples and best practices.
- Sample app refactored to demonstrate table data patterns with centralized validation logic.
- New utility classes added:
PersonValidator,PersonFilterMatcher,PersonFilterStateFactory,DefaultFormatRulesProvider, andPersonSorter. PersonTableDatamodel introduced in sample to showcase shared state management across table components.
Compare: v1.7.0...v1.7.1
- Added: Table footer support with full customization and pinning capabilities.
- New
footerDSL inColumnSpecbuilder for defining per-column footer content. TableSettings.showFooterenables footer row rendering below table body.TableSettings.footerPinnedcontrols whether footer stays pinned at the bottom (non-embedded tables only).- Footer respects pinned column configuration for consistent horizontal scrolling behavior.
TableColorsextended withfooterContainerColorandfooterContentColorproperties.TableDimensionsextended withfooterHeightproperty for customizable footer sizing.
- New
- Changed: Terminology update from "fixed" to "pinned" columns for better clarity.
TableSettings.fixedColumnsCount→pinnedColumnsCount(deprecated withReplaceWithmigration).TableSettings.fixedColumnsSide→pinnedColumnsSide(deprecated withReplaceWithmigration).FixedSideenum →PinnedSideenum (deprecated as typealias for backward compatibility).FixedColumnState→PinnedColumnState(internal state class renamed).TableDimensions.fixedColumnDividerThickness→pinnedColumnDividerThickness(deprecated withReplaceWithmigration).- All internal references updated to use "pinned" terminology throughout the codebase.
- Changed: Refactored
TableDefaultsinto a dedicated object with factory methods.- Extracted from
TableColors.ktto newTableDefaults.ktmodule for better organization. TableDefaults.colors()composable for creating color schemes with Material 3 theme defaults.TableDefaults.standardDimensions()for comfortable spacing and standard sizes (52dp rows, 56dp header).TableDefaults.compactDimensions()for minimal spacing and compact sizes (36dp rows, 40dp header).TableDimensionsconstructor now requires all parameters (no default values) to encourage explicit configuration.
- Extracted from
- Fixed: Auto-width adjustment for embedded tables now uses dedicated
ApplyAutoWidthEffectutility.- Resolves issues with incorrect column width calculations in nested table scenarios.
- Ensures embedded tables properly measure and apply auto-width independently from parent tables.
Compare: v1.6.4...v1.7.0
- Added:
TableState.tableWidthcomputed property to dynamically calculate total table width based on visible columns and their widths.- Automatically recalculates when column order, widths, or visible columns change using
derivedStateOf. - Accounts for both regular column widths and divider widths, including special handling for fixed column dividers.
- Eliminates need for manual width computation in row-embedded content and other custom layouts.
- Automatically recalculates when column order, widths, or visible columns change using
- Removed:
calculateTableWidth()function fromLayoutUtils.ktin favor of centralizedtableWidthproperty inTableState. - Changed: Internal visibility improvements and code cleanup:
- Changed
tableKeyboardNavigationmodifier from public to internal as it's not part of the public API. - Simplified
LocalTableStatedeclaration with explicit type annotation. - Minor formatting adjustments to KDoc comments and code structure.
- Changed
- Fixed: Row-embedded content (e.g., nested tables) now uses its own width instead of
tableWidthfor proper width alignment.
Compare: v1.6.3...v1.6.4
- Added:
TableState.recalculateAutoWidths()method for manual column width recalculation.- Useful for deferred/paginated data loading scenarios where initial auto-width calculation occurred on empty data.
- After data loads and content is measured, call this method to recompute column widths based on actual content.
Compare: v1.6.1...v1.6.3
- Added: Support for fully custom filters with renderer and state provider, enabling flexible and consistent custom
filter UI and behavior.
- New
TableFilterType.Custominterface allows defining custom filter types with dedicated composable UI. CustomFilterStateProviderinterface for building chip text and managing custom filter state.CustomFastFiltercomponent for rendering custom fast filters with animated visibility.CustomFiltercomponent for rendering custom filters in filter panels with action buttons.- Sample implementation includes
NumericRangeFilterwith range slider, histogram visualization, and predefined range buttons.
- New
Compare: v1.6.0...v1.6.1
- Added: Row-scoped cell editing mode with custom edit UI, validation, and keyboard navigation.
- Enable editing via
TableSettings(editingEnabled = true). - Use
EditableTable<T, C, E>composable for tables with editing support. - Declare editable columns with
editableTableColumns<T, C, E> { ... }DSL and per-celleditCellcontent. - Lifecycle callbacks:
onRowEditStart,onRowEditComplete,onEditCancelledfor validation and state management. - Keyboard navigation: Enter/Done moves to next editable cell, Escape cancels editing (desktop targets).
- Double-click any editable cell to enter row edit mode; all editable cells in the row become active simultaneously.
- Enable editing via
- Added:
TableCellTextFieldcomponent for text editing inside table cells.- Focus integration via
syncEditCellFocus()modifier ensures correct keyboard navigation and focus handling. - Compact layout with reduced paddings and optional border visibility for dense table rows.
- Visual consistency with Material 3 inputs used throughout table UI.
- Supports error states, keyboard actions, and customizable styling.
- Focus integration via
- Added:
EditCellFocusSync.ktmodule for coordinating focus between table state and editable cell composables. - Changed:
TableTextFieldvisibility changed from internal to public for reuse in custom filter implementations. - Changed: Filter components enhanced with configurable border visibility and improved layout:
- Added
showBorderparameter toTableTextField, date filters, and number filters. - Adjusted filter row height for better visual consistency.
- Number range slider text aligned to end for improved readability.
- Added
- Changed: Major refactoring of
TableStateto support editing mode, edit cell tracking, and edit lifecycle. - Changed:
ColumnSpecAPI extended witheditCellDSL for defining per-cell edit content. - Changed: Sample app updated with comprehensive editing demo including validation, error handling, and state management.
Compare: v1.5.1...v1.6.0
- Fixed: Ensure
TableTextField(table text field) uses the current theme's default text style to improve text visibility and consistency with app theming. - Removed: Unused
okioanddndreferences from build scripts; updated documentation to reflect removed third-party libraries.
Compare: v1.5.0...v1.5.1
- Added: Fixed (pinned) columns support with configurable side and count via
TableSettings.- New
fixedColumnsCountandfixedColumnsSideproperties allow pinning one or more columns on the left or right side of the table header and body. - Fixed columns remain visible while horizontally scrolling the rest of the table.
- Visual separators and z-index handling ensure clear separation between fixed and scrollable columns.
- New
- Added: Public access to
TableState.settingsandTableState.dimensionsto simplify integration with custom UI controls and preview tooling.
Compare: v1.4.1...v1.5.0
BREAKING CHANGES:
- Removed:
rowLeadingandrowTrailingparameters from allTablecomposable functions.- These parameters previously allowed rendering custom content before or after table rows.
- Migration: Use regular table columns defined via
ColumnSpecinstead. For leading content (e.g., checkboxes, avatars), define a dedicated column at the start of your column list. For trailing content (e.g., action buttons), add a column at the end. - Example:
// Before (1.4.0) Table( rowLeading = { item -> Checkbox(...) }, rowTrailing = { item -> IconButton(...) }, columns = dataColumns, // ... ) // After (1.4.1) val columns = tableColumns<Item, Field> { // Leading column for checkbox column(Field.Select, valueOf = { it }) { width(48.dp) cell { Checkbox(...) } } // Your data columns // ... // Trailing column for actions column(Field.Actions, valueOf = { it }) { width(64.dp) cell { IconButton(...) } } } Table( columns = columns, // ... )
- Removed: All internal infrastructure related to
rowLeading/rowTrailing:hasLeading,leadingColumnWidth,rowLeadingPresent,leadingOffsetparameters removed from internal functions.RowLeadingSectioncomponent removed.
Benefits of this change:
- Simplified API with fewer special-case parameters.
- Leading/trailing content now benefits from full column capabilities: sorting, resizing, filtering, custom styling, etc.
- More consistent and flexible table architecture.
Compare: v1.4.0...v1.4.1
- Added: Support for embedded detail tables via the
embeddedflag androwEmbeddedslot for rendering nested tables inside parent rows. - Added:
DisabledTableFiltertype to explicitly disable filtering and conditional formatting conditions for specific columns while still satisfying per-column filter type requirements.
Compare: v1.3.1...v1.4.0
- Changed: Updated Kotlin to 2.2.21 and Compose Multiplatform to 1.9.2.
Compare: v1.3.0...v1.3.1
- Added: Fast filter components with animated visibility and synchronized state management for boolean, enum, number, text, and date filters.
- Added: Date filter state management with synchronized external state and debounce handling for improved filtering functionality.
- Added:
enableDragToScrollsetting toTableSettingsfor customizable scroll behavior. - Added: Custom
TableTextFieldcomponent with configurable padding for consistent styling across filter components. - Changed: Converted all list types to immutable collections (
ImmutableList) for better performance, thread safety, and prevention of unintended modifications. - Fixed: Scroll to top on sort change for better user experience.
- Fixed: Updated
LaunchedEffectdependencies to track table state for correct cell selection handling. - Chore: Sample app updated with horizontal scrolling toolbar, new demo data, and Position enum.
- Chore: Documentation updated with Immutable Collections section in README.
Compare: v1.2.2...v1.3.0
- Added: Inertial fling support with velocity tracking and decay animation for smoother scroll momentum.
- Fixed: Added table state dependency to
LaunchedEffectin auto width effect and measurement utilities for correct recomposition and measurement updates.
Compare: v1.2.1...v1.2.2
- Fixed: Render sticky header for unordered list.
Compare: v1.2.0...v1.2.1
- Added: Group by functionality with customizable group headers and sticky positioning.
- Added: Column header dropdown menu with group by option for enhanced data organization.
- Fixed: Viewport scrolling logic and cell visibility calculations for improved user interaction.
- Changed: Extracted cell visibility logic and nested scroll handling for better user experience.
- Chore: Unused filter expression class to clean up codebase.
Compare: v1.1.3...v1.2.0
- Fixed: Resolved header resizing bug that could cause column misalignment during dynamic layout updates.
Compare: v1.1.2...v1.1.3
- Changed: Table core and interaction internals updated (layout, dimensions, keyboard navigation, viewport utils) and sample columns updated to the new header API.
Compare: v1.1.1...v1.1.2
- Fixed: Cell selection border now covers the full cell height in dynamic row height mode.
- Fixed: Vertical scrolling to the selected cell behaves like Excel — only the next/previous row is revealed without jumping.
- Added: Precise row height measurement and caching to support minimal, direction-aware scrolling.
- Added: Cache of measured row heights is automatically cleared when
itemsCountchanges (new data loaded).
Compare: v1.1.0...v1.1.1
- Added: Auto-fit column widths based on content (measurement utilities and smart sizing).
- Added: Dynamic row height with min/max constraints via table settings and column specifications.
- Added: Keyboard navigation and cell selection; improved cell visibility handling.
- Changed: Refactored
TableHeaderfor more stable layout and interaction handling. - Changed: Dependencies updated; deprecated modules removed.
- Changed: Samples updated (JS/WASM styles, better demo data and layout).
- Fixed: Header column animation during resizing.
Compare: v1.0.3...v1.1.0 on GitHub (https://github.com/White-Wind-LLC/table/compare/v1.0.3...main).