---
title: "SwipeToReveal"
description: "`SwipeToReveal` Material composable. This adds the option to configure up to two additional
actions on a Composable: a mandatory `primaryAction` and an optional `secondaryAction`. These
actions are initially hidden (unless `RevealState` is created with an initial value other than
`RevealValue.Covered`) and revealed only when the `content` is swiped - the action buttons can
then be clicked. A full swipe of the `content` triggers the `onSwipePrimaryAction` callback,
which is expected to match the `primaryAction`'s onClick callback. Custom accessibility actions
should always be added to the content using `Modifier.semantics` - examples are shown in the code
samples."
type: "component"
---

<div class='type'>Composable Component</div>



`SwipeToReveal` Material composable. This adds the option to configure up to two additional
actions on a Composable: a mandatory `primaryAction` and an optional `secondaryAction`. These
actions are initially hidden (unless `RevealState` is created with an initial value other than
`RevealValue.Covered`) and revealed only when the `content` is swiped - the action buttons can
then be clicked. A full swipe of the `content` triggers the `onSwipePrimaryAction` callback,
which is expected to match the `primaryAction`'s onClick callback. Custom accessibility actions
should always be added to the content using `Modifier.semantics` - examples are shown in the code
samples.

<a id='references'></a>

<div class='sourceset sourceset-android'>Android</div>


```kotlin
@Composable
public fun SwipeToReveal(
    primaryAction: @Composable SwipeToRevealScope.() -> Unit,
    onSwipePrimaryAction: () -> Unit,
    modifier: Modifier = Modifier,
    secondaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null,
    undoPrimaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null,
    undoSecondaryAction: (@Composable SwipeToRevealScope.() -> Unit)? = null,
    revealState: RevealState = rememberRevealState(),
    revealDirection: RevealDirection = RevealDirection.RightToLeft,
    hasPartiallyRevealedState: Boolean = true,
    gestureInclusion: GestureInclusion =
        if (revealDirection == Bidirectional) {
            bidirectionalGestureInclusion
        } else {
            gestureInclusion(revealState)
        },
    content: @Composable () -> Unit,
)
```


#### Parameters

| | |
| --- | --- |
| primaryAction | The primary action of this component. `SwipeToRevealScope.PrimaryActionButton` should be used to create a button for this slot. If `undoPrimaryAction` is provided, the undo button will be displayed after `SwipeToReveal` has animated to the revealed state and the primary action button has been hidden. |
| onSwipePrimaryAction | A callback which will be triggered when a full swipe is performed. It is expected that the same callback is given to `SwipeToRevealScope.PrimaryActionButton`s onClick action. If `undoPrimaryAction` is provided, that will be displayed after the swipe gesture is completed. |
| modifier | `Modifier` to be applied on the composable. |
| secondaryAction | Optional secondary action of this component. `SwipeToRevealScope.SecondaryActionButton` should be used to create a button for this slot. If `undoSecondaryAction` is provided, the undo button will be displayed after `SwipeToReveal` has animated to the revealed state and the secondary action button has been hidden. |
| undoPrimaryAction | Optional undo action for the primary action of this component. `SwipeToRevealScope.UndoActionButton` should be used to create a button for this slot. Displayed after `SwipeToReveal` has animated to the revealed state and the primary action button has been hidden. |
| undoSecondaryAction | Optional undo action for the secondary action of this component, displayed after `SwipeToReveal` has animated to the revealed state and the secondary action button has been hidden. `undoSecondaryAction` is ignored if the secondary action has not been specified. `SwipeToRevealScope.UndoActionButton` should be used to create a button for this slot. |
| revealState | `RevealState` of the `SwipeToReveal`. |
| revealDirection | The direction from which `SwipeToReveal` can reveal the actions. It is strongly recommended to respect the default value of `RightToLeft` to avoid conflicting with the system-side swipe-to-dismiss gesture. |
| hasPartiallyRevealedState | Determines whether the intermediate states `RightRevealing` and `LeftRevealing` are used. These indicate a settled state, where the primary action is partially revealed. By default, partially revealed state is allowed for single actions - set to false to make actions complete when swiped instead. This flag has no effect if a secondary action is provided (when there are two actions, the component always allows the partially revealed states). |
| gestureInclusion | Provides fine-grained control so that touch gestures can be excluded when they start in a certain region. An instance of `GestureInclusion` can be passed in here which will determine via `GestureInclusion.ignoreGestureStart` whether the gesture should proceed or not. By default, `gestureInclusion` allows gestures everywhere for when `revealState` contains anchors for both directions (see `bidirectionalGestureInclusion`). If it doesn't, then it allows gestures everywhere, except a zone on the left edge, which is used for swipe-to-dismiss (see `gestureInclusion`). |
| content | The content that will be initially displayed over the other actions provided. Custom accessibility actions should always be added to the content using `Modifier.semantics` - examples are shown in the code samples. |






## Code Examples
### SwipeToRevealNoPartialRevealWithScalingLazyColumnSample
```kotlin
@Preview
@Composable
fun SwipeToRevealNoPartialRevealWithScalingLazyColumnSample() {
    val slcState = rememberScalingLazyListState()
    val messages = remember {
        mutableStateListOf<String>().apply {
            for (i in 1..100) {
                add("Message #${i}")
            }
        }
    }
    ScalingLazyColumn(
        state = slcState,
        contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp),
        modifier = Modifier.background(Color.Black),
    ) {
        items(items = messages, key = { it }) { message ->
            SwipeToReveal(
                hasPartiallyRevealedState = false,
                primaryAction = {
                    PrimaryActionButton(
                        onClick = { messages.remove(message) },
                        icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
                        text = { Text("Delete") },
                    )
                },
                onSwipePrimaryAction = { messages.remove(message) },
            ) {
                Button(
                    modifier =
                        Modifier.fillMaxWidth().semantics {
                            // Use custom actions to make the primary action accessible
                            customActions =
                                listOf(
                                    CustomAccessibilityAction("Delete") {
                                        messages.remove(message)
                                        true
                                    }
                                )
                        },
                    onClick = {},
                ) {
                    Text(message, modifier = Modifier.fillMaxSize())
                }
            }
        }
    }
}
```
### SwipeToRevealSample
```kotlin
@Composable
fun SwipeToRevealSample() {
    SwipeToReveal(
        primaryAction = {
            PrimaryActionButton(
                onClick = { /* This block is called when the primary action is executed. */ },
                icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
                text = { Text("Delete") },
            )
        },
        onSwipePrimaryAction = { /* This block is called when the full swipe gesture is performed. */
        },
        secondaryAction = {
            SecondaryActionButton(
                onClick = { /* This block is called when the secondary action is executed. */ },
                icon = { Icon(Icons.Outlined.MoreVert, contentDescription = "Options") },
            )
        },
        undoPrimaryAction = {
            UndoActionButton(
                onClick = { /* This block is called when the undo primary action is executed. */ },
                text = { Text("Undo Delete") },
            )
        },
    ) {
        Button(
            modifier =
                Modifier.fillMaxWidth().semantics {
                    // Use custom actions to make the primary and secondary actions accessible
                    customActions =
                        listOf(
                            CustomAccessibilityAction("Delete") {
                                /* Add the primary action click handler here */
                                true
                            },
                            CustomAccessibilityAction("Options") {
                                /* Add the secondary click handler here */
                                true
                            },
                        )
                },
            onClick = {},
        ) {
            Text("This Button has two actions", modifier = Modifier.fillMaxSize())
        }
    }
}
```
### SwipeToRevealSingleActionCardSample
```kotlin
@Composable
fun SwipeToRevealSingleActionCardSample() {
    SwipeToReveal(
        primaryAction = {
            PrimaryActionButton(
                onClick = { /* This block is called when the primary action is executed. */ },
                icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
                text = { Text("Delete") },
                modifier = Modifier.height(SwipeToRevealDefaults.LargeActionButtonHeight),
            )
        },
        onSwipePrimaryAction = { /* This block is called when the full swipe gesture is performed. */
        },
        undoPrimaryAction = {
            UndoActionButton(
                onClick = { /* This block is called when the undo primary action is executed. */ },
                text = { Text("Undo Delete") },
            )
        },
    ) {
        Card(
            modifier =
                Modifier.fillMaxWidth().semantics {
                    // Use custom actions to make the primary action accessible
                    customActions =
                        listOf(
                            CustomAccessibilityAction("Delete") {
                                /* Add the primary action click handler here */
                                true
                            }
                        )
                },
            onClick = {},
        ) {
            Text(
                "This Card has one action, and the revealed button is taller",
                modifier = Modifier.fillMaxSize(),
            )
        }
    }
}
```
### SwipeToRevealWithScalingLazyColumnSample
```kotlin
@Preview
@Composable
fun SwipeToRevealWithScalingLazyColumnSample() {
    val slcState = rememberScalingLazyListState()
    val coroutineScope = rememberCoroutineScope()
    val messages = remember {
        mutableStateListOf<String>().apply {
            for (i in 1..100) {
                add("This Button $i has two actions")
            }
        }
    }
    ScalingLazyColumn(
        state = slcState,
        contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp),
        modifier = Modifier.background(Color.Black),
    ) {
        items(items = messages, key = { it }) { message ->
            val revealState = rememberRevealState()
            // SwipeToReveal should be reset to covered when scrolling occurs.
            LaunchedEffect(slcState.isScrollInProgress) {
                if (
                    slcState.isScrollInProgress && revealState.currentValue != RevealValue.Covered
                ) {
                    coroutineScope.launch {
                        revealState.animateTo(targetValue = RevealValue.Covered)
                    }
                }
            }
            SwipeToReveal(
                revealState = revealState,
                primaryAction = {
                    PrimaryActionButton(
                        onClick = { messages.remove(message) },
                        icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
                        text = { Text("Delete") },
                    )
                },
                onSwipePrimaryAction = { messages.remove(message) },
                secondaryAction = {
                    SecondaryActionButton(
                        onClick = { /* This block is called when the secondary action is executed. */
                        },
                        icon = { Icon(Icons.Outlined.MoreVert, contentDescription = "Options") },
                    )
                },
            ) {
                Button(
                    modifier =
                        Modifier.fillMaxWidth().semantics {
                            // Use custom actions to make the primary and secondary actions
                            // accessible
                            customActions =
                                listOf(
                                    CustomAccessibilityAction("Delete") {
                                        messages.remove(message)
                                        true
                                    },
                                    CustomAccessibilityAction("Options") {
                                        /* Add the secondary click handler here */
                                        true
                                    },
                                )
                        },
                    onClick = {},
                ) {
                    Text(message, modifier = Modifier.fillMaxSize())
                }
            }
        }
    }
}
```
### SwipeToRevealWithTransformingLazyColumnSample
```kotlin
@Preview
@Composable
fun SwipeToRevealWithTransformingLazyColumnSample() {
    val transformationSpec = rememberTransformationSpec()
    val tlcState = rememberTransformingLazyColumnState()
    val coroutineScope = rememberCoroutineScope()
    val messages = remember {
        mutableStateListOf<String>().apply {
            for (i in 1..100) {
                add("Message #${i}")
            }
        }
    }
    TransformingLazyColumn(
        state = tlcState,
        contentPadding = PaddingValues(horizontal = 16.dp, vertical = 20.dp),
        modifier = Modifier.background(Color.Black),
    ) {
        items(items = messages, key = { it }) { message ->
            val revealState = rememberRevealState()
            // SwipeToReveal should be reset to covered when scrolling occurs.
            LaunchedEffect(tlcState.isScrollInProgress) {
                if (
                    tlcState.isScrollInProgress && revealState.currentValue != RevealValue.Covered
                ) {
                    coroutineScope.launch {
                        revealState.animateTo(targetValue = RevealValue.Covered)
                    }
                }
            }
            SwipeToReveal(
                primaryAction = {
                    PrimaryActionButton(
                        onClick = { messages.remove(message) },
                        icon = { Icon(Icons.Outlined.Delete, contentDescription = "Delete") },
                        text = { Text("Delete") },
                        modifier = Modifier.height(SwipeToRevealDefaults.LargeActionButtonHeight),
                    )
                },
                revealState = revealState,
                onSwipePrimaryAction = { messages.remove(message) },
                modifier =
                    Modifier.transformedHeight(this@items, transformationSpec)
                        .animateItem()
                        .graphicsLayer {
                            with(transformationSpec) {
                                applyContainerTransformation(scrollProgress)
                            }
                            // Is needed to disable clipping.
                            compositingStrategy = CompositingStrategy.ModulateAlpha
                            clip = false
                        },
            ) {
                TitleCard(
                    onClick = {},
                    title = { Text(message) },
                    subtitle = { Text("Subtitle") },
                    modifier =
                        Modifier.semantics {
                            // Use custom actions to make the primary action accessible
                            customActions =
                                listOf(
                                    CustomAccessibilityAction("Delete") {
                                        messages.remove(message)
                                        true
                                    }
                                )
                        },
                ) {
                    Text("Message body which extends over multiple lines to extend the card")
                }
            }
        }
    }
}
```

