Edge-to-edge support on Android 15+
Table of contents
Edge-to-edge(opens in a new tab) enforcement ensures your app content fills the entire screen of a device. Starting with Android 15 (API level 35), this behavior is enabled by default for all apps.
Implications and potential issues
With edge-to-edge enabled, app content often extends beneath the status and navigation bars. This can make parts of your user interface (UI) difficult to read or interact with, since elements may be obscured by system components.
Proper handling is crucial to ensure your app content is fully visible and interactive.
Goal of proper edge-to-edge handling
The goal is to ensure all app content is fully visible and interactive. This article will cover handling edge-to-edge behavior using both Jetpack Compose and traditional XML layouts.
Compose approach
The following snippet demonstrates a common problem in Compose:
EdgeToEdgeTestTheme { LazyColumn { items(100) { Text( text = "Item number $it", modifier = Modifier .fillMaxWidth() .padding(16.dp) ) } }}The result looks like this.

Here, the list content scrolls beneath the status and navigation bars.
Solution with Scaffold
A simple solution is to use Scaffold, which automatically handles system insets. The LazyColumn can then take advantage of the paddingValues provided by Scaffold:
EdgeToEdgeTestTheme { Scaffold { paddingValues -> LazyColumn( modifier = Modifier.padding(paddingValues) ) { items(100) { Text( text = "Item number $it", modifier = Modifier .fillMaxWidth() .padding(16.dp) ) } } }}Now the content is drawn properly.

This approach works with all composables — not just LazyColumn — making it flexible for any UI layout. The content is fully visible and remains interactable at all times.
Handling cases without Scaffold
If you’re not using Scaffold, content may still extend beneath system bars:
EdgeToEdgeTestTheme { Text( modifier = Modifier .fillMaxSize() .background(Color.LightGray), text = LoremIpsum(words = 1000).values.joinToString { it } )}
To fix this, apply Modifier.safeContentPadding():
EdgeToEdgeTestTheme { Text( modifier = Modifier .fillMaxSize() .background(Color.LightGray) .safeContentPadding(), text = LoremIpsum(words = 1000).values.joinToString { it } )}The content is now fully visible.

XML approach
Here’s a basic example showing the issue in XML:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.textView) textView.text = LoremIpsum(words = 1000).values.joinToString { it }}activity_main.xml:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent">
<TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/background_light" android:textColor="@color/black" />
</LinearLayout>The content will be drawn beneath the system bars.

Applying window insets
To fix the problem, programmatically apply window insets:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) enableEdgeToEdge() setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.textView) textView.text = LoremIpsum(words = 1000).values.joinToString { it }
ViewCompat.setOnApplyWindowInsetsListener(textView) { v, windowInsets ->
// Here you need to determine which specific insets you want to combine with your `TextView` insets. // Choosing `WindowInsetsCompat.Type.systemBars()` would mean both status bar and navigation bar insets. val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) v.updateLayoutParams<ViewGroup.MarginLayoutParams> { leftMargin = insets.left topMargin = insets.top bottomMargin = insets.bottom rightMargin = insets.right }
// Return `CONSUMED` if you don't want the window insets to keep passing // down to descendant views. Otherwise, just return `windowInsets WindowInsetsCompat.CONSUMED`. }}Now the content is fully visible and interactive.

Conclusion
This post explored approaches using both Compose and XML to handle edge-to-edge behavior on Android 15+. These methods ensure your app content remains fully visible and interactive, keeping system bars from overlapping any UI elements.
With these strategies, you can confidently adopt edge-to-edge layouts while maintaining usability and accessibility.