Posted by Meghan Mehta – Developer Relations Engineer and Nick Butcher – Product Supervisor
At the moment, the Jetpack Compose August ‘25 launch is secure. This launch incorporates model 1.9 of core compose modules (see the complete BOM mapping), introducing new APIs for rendering shadows, 2D scrolling, wealthy styling of textual content transformations, improved checklist efficiency, and extra!
To make use of at present’s launch, improve your Compose BOM model to 2025.08.00:
implementation(platform("androidx.compose:compose-bom:2025.08.00"))
Shadows
We’re completely happy to introduce two extremely requested modifiers: Modifier.dropShadow() and Modifier.innerShadow() permitting you to render box-shadow results (in comparison with the prevailing Modifier.shadow() which renders elevation primarily based shadows primarily based on a lighting mannequin).
Modifier.dropShadow()
The dropShadow() modifier attracts a shadow behind your content material. You possibly can add it to your composable chain and specify the radius, shade, and unfold. Keep in mind, content material that ought to seem on high of the shadow (like a background) ought to be drawn after the dropShadow() modifier.
@Composable @Preview(showBackground = true) enjoyable SimpleDropShadowUsage() { val pinkColor = Shade(0xFFe91e63) val purpleColor = Shade(0xFF9c27b0) Field(Modifier.fillMaxSize()) { Field( Modifier .measurement(200.dp) .align(Alignment.Middle) .dropShadow( RoundedCornerShape(20.dp), dropShadow = DropShadow( 15.dp, shade = pinkColor, unfold = 10.dp, alpha = 0.5f ) ) .background( purpleColor, form = RoundedCornerShape(20.dp) ) ) } }

Modifier.innerShadow()
The Modifier.innerShadow() attracts shadows on the inset of the supplied form:
@Composable @Preview(showBackground = true) enjoyable SimpleInnerShadowUsage() { val pinkColor = Shade(0xFFe91e63) val purpleColor = Shade(0xFF9c27b0) Field(Modifier.fillMaxSize()) { Field( Modifier .measurement(200.dp) .align(Alignment.Middle) .background( purpleColor, form = RoundedCornerShape(20.dp) ) .innerShadow( RoundedCornerShape(20.dp), innerShadow = InnerShadow( 15.dp, shade = Shade.Black, unfold = 10.dp, alpha = 0.5f ) ) ) } }

The order for inside shadows is essential. The inside shadow attracts on high of the content material, so for the instance above, we wanted to maneuver the inside shadow modifier after the background modifier. We’d have to do one thing related when utilizing it on high of one thing like an Picture. On this instance, we’ve positioned a separate Field to render the shadow within the layer above the picture:
@Composable @Preview(showBackground = true) enjoyable PhotoInnerShadowExample() { Field(Modifier.fillMaxSize()) { val form = RoundedCornerShape(20.dp) Field( Modifier .measurement(200.dp) .align(Alignment.Middle) ) { Picture( painter = painterResource(id = R.drawable.cape_town), contentDescription = "Picture with Interior Shadow", contentScale = ContentScale.Crop, modifier = Modifier.fillMaxSize() .clip(form) ) Field( modifier = Modifier.fillMaxSize() .innerShadow( form, innerShadow = InnerShadow(15.dp, unfold = 15.dp) ) ) } } }

New Visibility modifiers
Compose UI 1.8 launched onLayoutRectChanged, a brand new performant option to monitor the situation of components on display screen. We’re constructing on high of this API to assist frequent use circumstances by introducing onVisibilityChanged and onFirstVisible. These APIs settle for non-obligatory parameters for the minimal fraction or period of time the merchandise has been seen for earlier than invoking your motion.
Use onVisibilityChanged for UI modifications or unintended effects that ought to occur primarily based on visibility, like robotically enjoying and pausing movies or beginning an animation:
LazyColumn { gadgets(feedData) { video -> VideoRow( video, Modifier.onVisibilityChanged(minDurationMs = 500, minFractionVisible = 1f) { seen -> if (seen) video.play() else video.pause() }, ) } }
Use onFirstVisible to be used circumstances if you want to react to a component first changing into seen on display screen for instance to log impressions:
LazyColumn { gadgets(100) { Field( Modifier // Log impressions when merchandise has been seen for 500ms .onFirstVisible(minDurationMs = 500) { /* log impression */ } .clip(RoundedCornerShape(16.dp)) .drawBehind { drawRect(backgroundColor) } .fillMaxWidth() .peak(100.dp) ) } }
Wealthy styling in OutputTransformation
BasicTextField now helps making use of kinds like shade and font weight from inside an OutputTransformation.
The brand new TextFieldBuffer.addStyle() strategies allow you to apply a SpanStyle or ParagraphStyle to vary the looks of textual content, with out altering the underlying TextFieldState. That is helpful for visually formatting enter, like telephone numbers or bank cards. This methodology can solely be referred to as inside an OutputTransformation.
// Format a telephone quantity and shade the punctuation val phoneTransformation = OutputTransformation { // 1234567890 -> (123) 456-7890 if (size == 10) { insert(0, "(") insert(4, ") ") insert(9, "-") // Shade the added punctuation val grey = Shade(0xFF666666) addStyle(SpanStyle(shade = grey), 0, 1) addStyle(SpanStyle(shade = grey), 4, 5) addStyle(SpanStyle(shade = grey), 9, 10) } } BasicTextField( state = myTextFieldState, outputTransformation = phoneTransformation )
LazyLayout
The constructing blocks of LazyLayout are all now secure! Try LazyLayoutMeasurePolicy, LazyLayoutItemProvider, and LazyLayoutPrefetchState to construct your personal Lazy parts.
Prefetch Enhancements
There at the moment are important scroll efficiency enhancements in Lazy Record and Lazy Grid with the introduction of recent prefetch conduct. Now you can outline a LazyLayoutCacheWindow to prefetch extra content material. By default, just one merchandise consists forward of time within the course of scrolling, and after one thing scrolls off display screen it’s discarded. Now you can customise the quantity of things forward to prefetch and behind to retain by means of a fraction of the viewport or dp measurement. While you choose into utilizing LazyLayoutCacheWindow, gadgets start prefetching within the forward space immediately.
The configuration entry level for that is on LazyListState, which takes within the cache window measurement:
@OptIn(ExperimentalFoundationApi::class) @Composable non-public enjoyable LazyColumnCacheWindowDemo() { // Prefetch gadgets 150.dp forward and retain gadgets 100.dp behind the seen viewport val dpCacheWindow = LazyLayoutCacheWindow(forward = 150.dp, behind = 100.dp) // Alternatively, prefetch/retain gadgets as a fraction of the checklist measurement // val fractionCacheWindow = LazyLayoutCacheWindow(aheadFraction = 1f, behindFraction = 0.5f) val state = rememberLazyListState(cacheWindow = dpCacheWindow) LazyColumn(state = state) { gadgets(1000) { Textual content(textual content = "$it", fontSize = 80.sp) } } }

Notice: Prefetch composes extra gadgets than are at the moment seen — the brand new cache window API will seemingly improve prefetching. Which means that merchandise’s LaunchedEffects and DisposableEffects might run earlier – don’t use this as a sign for visibility e.g. for impression monitoring. As a substitute, we advocate utilizing the brand new onFirstVisible and onVisibilityChanged APIs. Even if you happen to’re not manually customizing LazyLayoutCacheWindow now, keep away from utilizing composition results as a sign of content material visibility, as this new prefetch mechanism will likely be enabled by default in a future launch.
Scroll
2D Scroll APIs
Following the discharge of Draggable2D, Scrollable2D is now accessible, bringing two-dimensional scrolling to Compose. Whereas the prevailing Scrollable modifier handles single-orientation scrolling, Scrollable2D allows each scrolling and flinging in 2D. This lets you create extra complicated layouts that transfer in all instructions, corresponding to spreadsheets or picture viewers. Nested scrolling can also be supported, accommodating 2D eventualities.
val offset = bear in mind { mutableStateOf(Offset.Zero) } Field( Modifier.measurement(150.dp) .scrollable2D( state = rememberScrollable2DState { delta -> offset.worth = offset.worth + delta // replace the state delta // point out that we consumed all of the pixels accessible } ) .background(Shade.LightGray), contentAlignment = Alignment.Middle, ) { Textual content( "X=${offset.worth.x.roundToInt()} Y=${offset.worth.y.roundToInt()}", model = TextStyle(fontSize = 32.sp), ) }

Scroll Interop Enhancements
There are bug fixes and new options to enhance scroll and nested scroll interop with Views, together with the next:
- Fastened the dispatching of incorrect velocities throughout fling animations between Compose and Views.
- Compose now accurately invokes the View’s nested scroll callbacks within the applicable order.
Enhance crash evaluation by including supply information to stack traces
We’ve heard from you that it may be laborious to debug Compose crashes when your personal code doesn’t seem within the stack hint. To deal with this we’re offering a brand new, opt-in API to supply richer crash location particulars, together with composable names and places enabling you to:
- Effectively establish and resolve crash sources.
- Extra simply isolate crashes for reproducible samples.
- Examine crashes that beforehand solely confirmed inside stack frames.
Notice that we don’t advocate utilizing this API in launch builds as a result of efficiency influence of accumulating this additional info, nor does it work in minified apks.
To allow this function, add the road beneath to the appliance entry level. Ideally, this configuration ought to be carried out earlier than any compositions are created to make sure that the stack hint info is collected:
class App : Software() { override enjoyable onCreate() { // Allow just for debug taste to keep away from perf regressions in launch Composer.setDiagnosticStackTraceEnabled(BuildConfig.DEBUG) } }
New annotations and Lint checks
We’re introducing a brand new runtime-annotation library that exposes annotations utilized by the compiler and tooling (corresponding to lint checks). This enables non-Compose modules to make use of these annotations with no dependency on the Compose runtime library. The @Secure, @Immutable, and @StableMarker annotations have moved to runtime-annotation, permitting you to annotate lessons and capabilities that don’t rely upon Compose.
Moreover, we have now added two new annotations and corresponding lint checks:
- @RememberInComposition: An annotation that may mark constructors, capabilities, and property getters, to point that they need to not be referred to as instantly inside composition with out being remembered. Errors will likely be raised by a corresponding lint examine.
- @FrequentlyChangingValue: An annotation that may mark capabilities, and property getters, to point that they shouldn’t be referred to as instantly inside composition, as this will trigger frequent recompositions (for instance, marking scroll place values and animating values). Warnings are supplied by a corresponding lint examine.
Extra updates
- To simplify compatibility and enhance stability for lint examine assist, Compose now requires Android Gradle Plugin (AGP) / Lint model 8.8.2 or increased. Try this new documentation web page to study extra.
- Two new APIs have been added for context menus:
Get began
We recognize all bug studies and have requests submitted to our situation tracker. Your suggestions permits us to construct the APIs you want in your apps. Joyful composing!