What's new in Compose Multiplatform 1.9.0
Here are the highlights for this feature release:
See the full list of changes for this release on GitHub.
Dependencies
Gradle Plugin
org.jetbrains.compose
, version 1.9.0. Based on Jetpack Compose libraries:Compose Material3 libraries
org.jetbrains.compose.material3:1.9.0-beta06
. Based on Jetpack Material3 1.4.0-beta03.The stable version of the common Material3 library is based on Jetpack Compose Material3 1.3.2, but thanks to decoupled versions of Compose Multiplatform and Material3 you can choose a newer pre-release version for your project.
Compose Material3 Adaptive libraries
org.jetbrains.compose.material3.adaptive:adaptive*:1.2.0-alpha06
. Based on Jetpack Material3 Adaptive 1.2.0-alpha11Lifecycle libraries
org.jetbrains.androidx.lifecycle:lifecycle-*:2.9.4
. Based on Jetpack Lifecycle 2.9.2Navigation libraries
org.jetbrains.androidx.navigation:navigation-*:2.9.0
. Based on Jetpack Navigation 2.9.1Savedstate library
org.jetbrains.androidx.savedstate:savedstate:1.3.4
. Based on Jetpack Savedstate 1.3.1WindowManager Core library
org.jetbrains.androidx.window:window-core:1.4.0
. Based on Jetpack WindowManager 1.4.0
Across platforms
Parameters for the @Preview
annotation
The @Preview
annotation in Compose Multiplatform now includes additional parameters for configuring how a @Composable
function is rendered in design-time previews:
name
: The display name of the preview.group
: The group name for the preview, enabling the logical organization and selective display of related previews.widthDp
: The maximum width (in dp).heightDp
: The maximum height (in dp).locale
: The current locale of the application.showBackground
: A flag to apply the default background color to the preview.backgroundColor
: A 32-bit ARGB color integer defining the preview’s background color.
These new preview parameters are recognized and work in both IntelliJ IDEA and Android Studio.
Customizable shadows
In Compose Multiplatform 1.9.0, we’ve introduced customizable shadows, adopting Jetpack Compose’s new shadow primitives and APIs. In addition to the previously supported shadow
modifier, you can now use the new API to create more advanced and flexible shadow effects.
Two new primitives are available for creating different types of shadows: DropShadowPainter()
and InnerShadowPainter()
.
To apply these new shadows to UI components, configure shadow effects with the dropShadow
or innerShadow
modifiers:
- Box( Modifier.size(120.dp) .dropShadow( RectangleShape, DropShadow(12.dp) ) .background(Color.White) ) Box( Modifier.size(120.dp) .innerShadow( RectangleShape, InnerShadow(12.dp) ) )
You can draw shadows of any shape and color, or even use shadow geometry as a mask to create an inner gradient-filled shadow:

For details, see the shadow API reference.
New context menu API
We've adopted Jetpack Compose's new API for custom context menus in SelectionContainer
and BasicTextField
. The implementation is complete for iOS and web, while desktop has initial support.
To enable this new API, use the following setting at the application entry point:
For details, see the context menu API reference.
Material 3 Expressive theme
Compose Multiplatform now supports an experimental MaterialExpressiveTheme
from the Material 3 library. The expressive theming allows you to customize your Material Design app for a more personalized experience.
To use the Expressive theme:
Include the experimental version of Material 3:
implementation("org.jetbrains.compose.material3:material3:1.9.0-alpha04")Configure the overall theme of your UI elements using the
MaterialExpressiveTheme()
function. This function requires the@OptIn(ExperimentalMaterial3ExpressiveApi::class)
opt-in and allows you to specifycolorScheme
,motionScheme
,shapes
, andtypography
.
Material components, such as Button()
and Checkbox()
, will then automatically use the values you’ve provided.

Multiplatform targets in androidx.compose.runtime:runtime
To improve Compose Multiplatform's alignment with Jetpack Compose, we've added support for all targets directly into the androidx.compose.runtime:runtime
artifact.
The org.jetbrains.compose.runtime:runtime
artifact remains fully compatible and now serves as an alias.
runComposeUiTest()
with suspend
lambda
The runComposeUiTest()
function now accepts a suspend
lambda, allowing you to use suspending functions such as awaitIdle()
.
The new API guarantees correct test execution on all supported platforms, including proper asynchronous handling for web environments:
For JVM and native targets,
runComposeUiTest()
functions similarly torunBlocking()
, but skips delays.For web targets (Wasm and JS), it returns a
Promise
and executes the test body with delays skipped.
iOS
Frame rate configuration
Compose Multiplatform for iOS now supports configuring the preferred frame rate for rendering a composable. If an animation is stuttering, you may want to increase the frame rate. On the other hand, if the animation is slow or static, you may prefer running it at a lower frame rate to reduce power consumption.
You can set the preferred frame rate category as follows:
Alternatively, if you need a specific frame rate for a composable, you can define the preferred frame rate in frames per second using a non-negative number:
If you apply preferredFrameRate
multiple times within the same @Composable
tree, the highest specified value will be applied. However, the device's hardware may limit the supported frame rates, typically up to 120 Hz.
IME options
Compose Multiplatform 1.9.0 introduces support for iOS-specific IME customization for text input components. You can now use PlatformImeOptions
to configure native UIKit text input traits such as keyboard type, autocorrection, and return key behavior directly in the text field component:
Web
Compose Multiplatform for web in Beta
Compose Multiplatform for web is now in Beta, making it a great time to give it a try. Check out our blog post to learn more about the progress made to reach this milestone.
As we work toward a stable release, our roadmap includes:
Implementing support for drag-and-drop functionality in mobile browsers.
Improving accessibility support.
Addressing issues related to the
TextField
component.
Accessibility support
Compose Multiplatform now provides initial accessibility support for the web target. This version enables screen readers to access description labels and allows users to navigate and click buttons in accessible navigation mode.
In this version, the following features are not yet supported:
Accessibility for interop and container views with scrolls and sliders.
Traversal indexes.
You can define a component's semantic properties to provide accessibility services with various details, such as the component’s textual description, functional type, current state, or unique identifier.
For example, by setting Modifier.semantics { heading() }
on a composable, you inform accessibility services that this element acts as a heading, similar to a chapter or a subsection title in a document. Screen readers can then use this information for content navigation, allowing users to jump directly between headings.
Accessibility support is now enabled by default, but you can disable it at any time by adjusting isA11YEnabled
:
New API for embedding HTML content
With the new WebElementView()
composable function, you can seamlessly integrate HTML elements into your web application.
The embedded HTML element overlays the canvas area based on the size defined in your Compose code. It intercepts input events within that area, preventing those events from being received by Compose Multiplatform.
Here’s an example of WebElementView()
being used to create and embed an HTML element that displays an interactive map view within your Compose application:
Note that you can only use this function with the ComposeViewport
entry point, as CanvasBasedWindow
is deprecated.
Simplified API for binding to the navigation graph
Compose Multiplatform has introduced a new API for binding the browser’s navigation state to the NavController
:
The new function removes the need to interact directly with the window
API, simplifying both the Kotlin/Wasm and Kotlin/JS source sets.
The previously used Window.bindToNavigation()
function has been deprecated in favor of the new NavController.bindToBrowserNavigation()
function.
Before:
After:
Desktop
Configuring windows before display
Compose Multiplatform now includes new SwingFrame()
and SwingDialog()
composables. They are similar to the existing Window()
and DialogWindow()
functions but include an init
block.
Previously, you couldn't set certain window properties that had to be configured before display. The new init
block executes before your window or dialog appears on the screen, allowing you to configure properties like java.awt.Window.setType
or add event listeners that need to be ready early.
We recommend using the init
block only for properties that cannot be changed once the window or dialog is visible. For all other configurations, continue using the LaunchedEffect(window)
pattern to ensure your code remains compatible and works correctly with future updates.
Gradle plugin
Decoupled Material3 versioning
The versions and stability levels of the Material3 library and Compose Multiplatform Gradle plugin no longer have to be aligned. The compose.material3
DSL alias now references Material3 1.8.2 from the previous stable release of Jetpack Compose.
If you want to use a newer Material3 version with Expressive design support, replace the Material 3 dependency in build.gradle.kts
with the following:
Unified web distribution
The new composeCompatibilityBrowserDistribution
Gradle task combines Kotlin/JS and Kotlin/Wasm distributions into a single package. This allows Wasm applications to fall back to the JS target when modern Wasm features are not supported by a browser.