
In this article, we’ll learn how to implement the swipe to delete action in Jetpack Compose LazyColumn.
Prerequisites:
We’ll create the following output:

First, create an empty Compose project and open MainActivity. Create a Composable called MyUI() and call it from the onCreate(). We’ll write our code in it.
MainActivity for the Material 3 Jetpack Compose:
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AddCircle
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material3.DismissDirection
import androidx.compose.material3.DismissValue
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.SwipeToDismiss
import androidx.compose.material3.Text
import androidx.compose.material3.rememberDismissState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
MyUI()
}
}
}
}
}
}
@Composable
fun MyUI() {
}
MainActivity for the Material 2 Version:
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.items
import androidx.compose.material.DismissDirection
import androidx.compose.material.DismissValue
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.Icon
import androidx.compose.material.SwipeToDismiss
import androidx.compose.material.Text
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.outlined.AddCircle
import androidx.compose.material.icons.outlined.Delete
import androidx.compose.material.rememberDismissState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateListOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
YourProjectNameTheme(darkTheme = false) {
Column(
modifier = Modifier
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally
) {
MyUI()
}
}
}
}
}
@Composable
fun MyUI() {
}
Note: I am using the Material 3 APIs. If you are working with Material 2, you may see a slightly different appearance, but the code and animation will still work as expected.
Create a data class to store the list of people.
data class People(var id: Int, var name: String)
- id – It is the unique value for each item in the list. We need it for swiping the items.
- name – Name of the person.
Material 3 Jetpack Compose provides SwipeToDismiss() API from the version 1.1.0.
@Composable
@ExperimentalMaterial3Api
fun SwipeToDismiss(
state: DismissState,
background: @Composable RowScope.() -> Unit,
dismissContent: @Composable RowScope.() -> Unit,
modifier: Modifier = Modifier,
directions: Set<DismissDirection> = setOf(EndToStart, StartToEnd),
)
state – To manage the state of this component.
background – It is a composable that is visible behind the actual content when we swipe.
dismissContent – The content that can be dismissed. We add the list here.
modifier – An optional Modifier for this component.
directions – The set of directions in which the component can be dismissed.
Example:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyUI() {
// list for the lazy column
val peopleList = remember { mutableStateListOf<People>() }
val contextForToast = LocalContext.current.applicationContext
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 12.dp) // margin
) {
items(
items = peopleList,
key = { people ->
people.id
}
) { people ->
val dismissState = rememberDismissState()
// check if the user swiped
if (dismissState.isDismissed(direction = DismissDirection.EndToStart)) {
Toast.makeText(contextForToast, "Delete", Toast.LENGTH_SHORT).show()
peopleList.remove(people)
}
SwipeToDismiss(
state = dismissState,
directions = setOf(
DismissDirection.EndToStart
),
background = {
// this background is visible when we swipe.
// it contains the icon
// background color
val backgroundColor by animateColorAsState(
when (dismissState.targetValue) {
DismissValue.DismissedToStart -> Color.Red.copy(alpha = 0.8f)
else -> Color.White
}
)
// icon size
val iconScale by animateFloatAsState(
targetValue = if (dismissState.targetValue == DismissValue.DismissedToStart) 1.3f else 0.5f
)
Box(
Modifier
.fillMaxSize()
.background(color = backgroundColor)
.padding(end = 16.dp), // inner padding
contentAlignment = Alignment.CenterEnd // place the icon at the end (left)
) {
Icon(
modifier = Modifier.scale(iconScale),
imageVector = Icons.Outlined.Delete,
contentDescription = "Delete",
tint = Color.White
)
}
},
dismissContent = {
// list item
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = Color.White)
) {
Text(
text = people.name,
fontSize = 20.sp,
modifier = Modifier
.fillMaxSize()
.padding(top = 16.dp, bottom = 16.dp, start = 12.dp)
)
}
}
)
}
}
LaunchedEffect(key1 = Unit) {
peopleList.add(People(id = 1, name = "Morfydd Clark - Galadriel"))
peopleList.add(People(id = 2, name = "Robert Aramayo- Elrond"))
peopleList.add(People(id = 3, name = "Lloyd Owen - Elendil"))
peopleList.add(People(id = 4, name = "Markella Kavenagh - Nori"))
peopleList.add(People(id = 5, name = "Ismael Cruz Córdova - Arondir"))
peopleList.add(People(id = 6, name = "Nazanin Boniadi - Bronwyn"))
peopleList.add(People(id = 7, name = "Tyroe Muhafidin - Theo"))
}
}
data class People(var id: Int, var name: String)
Output:

We created peopleList object and added names to the list in the LaunchedEffect block. In the LazyColumn, we added the SwipeToDismiss() method.
First, we need the state object to track the swipe actions.
val dismissState = rememberDismissState()
It provides different methods and objects:
isDismissed():
fun isDismissed(direction: DismissDirection): Boolean
It returns true if the component has been dismissed in the given direction. There are two directions:
- DismissDirection.EndToStart – Swiping from left to right.
- DismissDirection.StartToEnd – From right to left.
In the background, we added the icon. The dismissState.targetValue informs us about the current drag status. It provides 3 values:
- DismissValue.DismissedToStart – It indicates the swiping from the left.
- DismissValue.DismissedToEnd – Swiping from the right.
- DismissValue.Default – No swiping.
We added icon size and background color based on the dismissState.targetValue.
The dismissContent contains the list items. We added the name values from the list here.
We can also add swiping in two directions, from left to right and right to left. Here is the complete code:
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun MyUI() {
// list for the lazy column
val peopleList = remember { mutableStateListOf<People>() }
val contextForToast = LocalContext.current.applicationContext
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(vertical = 12.dp)
) {
items(
items = peopleList,
key = { people ->
people.id
}
) { people ->
val dismissState = rememberDismissState()
if (dismissState.isDismissed(direction = DismissDirection.EndToStart)) {
// swiping from left to right
Toast.makeText(contextForToast, "Delete", Toast.LENGTH_SHORT).show()
peopleList.remove(people)
} else if (dismissState.isDismissed(direction = DismissDirection.StartToEnd)) {
// swiping from right to left
Toast.makeText(contextForToast, "Add", Toast.LENGTH_SHORT).show()
peopleList.remove(people)
}
SwipeToDismiss(
state = dismissState,
directions = setOf(
DismissDirection.EndToStart,
DismissDirection.StartToEnd
),
background = {
// background color
val backgroundColor by animateColorAsState(
when (dismissState.targetValue) {
DismissValue.DismissedToStart -> Color.Red.copy(alpha = 0.8f)
DismissValue.DismissedToEnd -> Color.Green.copy(alpha = 0.8f)
else -> Color.White
}
)
// icon
val iconImageVector = when (dismissState.targetValue) {
DismissValue.DismissedToEnd -> Icons.Outlined.AddCircle
else -> Icons.Outlined.Delete
}
// icon placement
val iconAlignment = when (dismissState.targetValue) {
DismissValue.DismissedToEnd -> Alignment.CenterStart
else -> Alignment.CenterEnd
}
// icon size
val iconScale by animateFloatAsState(
targetValue = if (dismissState.targetValue == DismissValue.Default) 0.5f else 1.3f
)
Box(
Modifier
.fillMaxSize()
.background(color = backgroundColor)
.padding(start = 16.dp, end = 16.dp), // inner padding
contentAlignment = iconAlignment
) {
Icon(
modifier = Modifier.scale(iconScale),
imageVector = iconImageVector,
contentDescription = null,
tint = Color.White
)
}
},
dismissContent = {
// list item
Column(
modifier = Modifier
.fillMaxWidth()
.background(color = Color.White)
) {
Text(
text = people.name,
fontSize = 20.sp,
modifier = Modifier
.fillMaxSize()
.padding(top = 16.dp, bottom = 16.dp, start = 12.dp)
)
}
}
)
}
}
LaunchedEffect(key1 = Unit) {
peopleList.add(People(id = 1, name = "Morfydd Clark - Galadriel"))
peopleList.add(People(id = 2, name = "Robert Aramayo- Elrond"))
peopleList.add(People(id = 3, name = "Lloyd Owen - Elendil"))
peopleList.add(People(id = 4, name = "Markella Kavenagh - Nori"))
peopleList.add(People(id = 5, name = "Ismael Cruz Córdova - Arondir"))
peopleList.add(People(id = 6, name = "Nazanin Boniadi - Bronwyn"))
peopleList.add(People(id = 7, name = "Tyroe Muhafidin - Theo"))
}
}
data class People(var id: Int, var name: String)
Output:

This is all about swipe actions in Jetpack Compose LazyColumn. I hope you have learned something new. If you have any doubts, leave a comment below.
Related Articles:
References: