---
title: Dialog
description: A modal dialog component with dismiss behavior and panel transitions.
---



```kotlin expandable title="DialogDemo.kt" githubUrl="https://github.com/composablehorizons/compose-unstyled/blob/main/demo/src/commonMain/kotlin/com/composeunstyled/demo/dialog/DialogDemo.kt"
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.LocalIndication
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.displayCutoutPadding
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.systemBarsPadding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import com.composeunstyled.DialogPanel
import com.composeunstyled.Scrim
import com.composeunstyled.Text
import com.composeunstyled.UnstyledButton
import com.composeunstyled.UnstyledDialog
import com.composeunstyled.demo.borderToken
import com.composeunstyled.demo.colors
import com.composeunstyled.demo.contentToken
import com.composeunstyled.demo.scrimToken
import com.composeunstyled.demo.surfaceToken
import com.composeunstyled.theme.Theme

@Preview
@Composable
fun DialogDemo() {
  var dialogVisible by remember { mutableStateOf(true) }
  Box(
    modifier = Modifier.fillMaxSize(),
    contentAlignment = Alignment.Center,
  ) {
    UnstyledButton(
      onClick = { dialogVisible = true },
      modifier = Modifier
        .clip(RectangleShape)
        .heightIn(32.dp)
        .background(Theme[colors][surfaceToken])
        .border(1.dp, Theme[colors][borderToken], RectangleShape),
      contentPadding = PaddingValues(horizontal = 10.dp),
      indication = LocalIndication.current,
    ) {
      Text("Show dialog")
    }

    UnstyledDialog(
      visible = dialogVisible,
      onDismissRequest = { dialogVisible = false },
      overlay = {
        Scrim(
          scrimColor = Theme[colors][scrimToken],
          enter = fadeIn(),
          exit = fadeOut(),
        )
      },
    ) {
      Box(
        modifier = Modifier
          .fillMaxSize(),
        contentAlignment = Alignment.Center,
      ) {
        DialogPanel(
          modifier = Modifier
            .padding(20.dp)
            .displayCutoutPadding()
            .systemBarsPadding()
            .widthIn(max = 560.dp)
            .padding(20.dp)
            .clip(RectangleShape)
            .background(Theme[colors][surfaceToken])
            .border(1.dp, Theme[colors][borderToken], RectangleShape),
          paneTitle = "Dialog",
          enter = scaleIn(initialScale = 0.8f) + fadeIn(tween(durationMillis = 250)),
          exit = scaleOut(targetScale = 0.6f) + fadeOut(tween(durationMillis = 150)),
        ) {
          Column {
            Column(Modifier.padding(start = 24.dp, top = 24.dp, end = 24.dp)) {
              Text(
                text = "Update Available",
                color = Theme[colors][contentToken],
                fontSize = 16.sp,
                lineHeight = 24.sp,
                fontWeight = FontWeight.Medium,
              )
              Spacer(Modifier.height(8.dp))
              Text(
                text = "A new version of the app is available. " +
                  "Please update to the latest version.",
                color = Theme[colors][contentToken],
              )
            }
            Spacer(Modifier.height(24.dp))
            UnstyledButton(
              onClick = { dialogVisible = false },
              modifier = Modifier
                .padding(12.dp)
                .align(Alignment.End)
                .clip(RectangleShape),
              indication = LocalIndication.current,
            ) {
              Text(
                "Update",
                modifier = Modifier.padding(horizontal = 12.dp, vertical = 8.dp),
                color = Theme[colors][contentToken],
              )
            }
          }
        }
      }
    }
  }
}
```



## Features

- Modal focus behavior
- Outside-click dismiss
- Back and Escape dismiss
- Panel enter and exit transitions

## Installation

```kotlin
implementation("com.composables:composeunstyled-dialog:2.10.0")
```

## Anatomy

```kotlin
UnstyledDialog(
  visible = visible,
  onDismissRequest = { visible = false },
) {
  DialogPanel {
  }
}
```

## Concepts

- `UnstyledDialog` renders dialog content in a modal layer.
- `DialogPanel` renders the focusable dialog content.

## Accessibility

Use the `paneTitle` parameter on `DialogPanel` when the dialog has a clear title.

## Code Examples

### Showing and hiding a dialog

Use the `visible` parameter to show the dialog and the `onDismissRequest` callback to update that state:

```kotlin expandable
var visible by remember { mutableStateOf(false) }

BasicText(
  text = "Show dialog",
  modifier = Modifier.clickable { visible = true },
)

UnstyledDialog(
  visible = visible,
  onDismissRequest = { visible = false },
) {
  DialogPanel {
    BasicText("Dialog content")
  }
}
```

### Adding an overlay behind a dialog

Use the `overlay` parameter to render content behind the dialog panel. `Scrim` provides a
ready-made overlay for dialogs.

```kotlin expandable
UnstyledDialog(
  visible = visible,
  onDismissRequest = { visible = false },
  overlay = { Scrim() },
) {
  DialogPanel {
    BasicText("Dialog content")
  }
}
```

### Changing dismiss behavior

Use the `properties` parameter to control how the dialog can be dismissed:

```kotlin expandable
UnstyledDialog(
  visible = visible,
  onDismissRequest = { visible = false },
  properties = DialogProperties(
    dismissOnBackPress = false,
    dismissOnClickOutside = false,
  ),
) {
  DialogPanel {
    BasicText("Dialog content")
  }
}
```

### Animating the dialog panel

Use the `enter` and `exit` parameters on `DialogPanel` to animate the dialog panel:

```kotlin expandable
UnstyledDialog(
  visible = visible,
  onDismissRequest = { visible = false },
) {
  DialogPanel(
    enter = fadeIn(),
    exit = fadeOut(),
  ) {
    BasicText("Dialog content")
  }
}
```

## API Reference

### UnstyledDialog

| Parameter | Type | Description |
|-----------|------|-------------|
| `visible` | `Boolean` |  |
| `onDismissRequest` | `() -> Unit` |  |
| `properties` | `DialogProperties` | Properties that control when the dialog needs to be dismissed (such as clicking outside of the panel or pressing Esc or Back. |
| `overlay` | `(DialogOverlayScope.() -> Unit)?` |  |
| `content` | `DialogScope.() -> Unit` | A `@Composable` function that provides a `DialogScope`. |
### DialogOverlayScope.Scrim

| Parameter | Type | Description |
|-----------|------|-------------|
| `modifier` | `Modifier` | `Modifier` for the Scrim |
| `scrimColor` | `Color` | Controls the color of the Scrim. The default color is Black with an alpha of 60%. |
| `enter` | `EnterTransition` | The `EnterTransition` when the Scrim enters the composition |
| `exit` | `ExitTransition` | The `ExitTransition` when the Scrim enters the composition |
### DialogScope.DialogPanel

| Parameter | Type | Description |
|-----------|------|-------------|
| `modifier` | `Modifier` | `Modifier` for the Scrim |
| `paneTitle` | `String?` |  |
| `enter` | `EnterTransition` | The `EnterTransition` when the Scrim enters the composition |
| `exit` | `ExitTransition` | The `ExitTransition` when the Scrim enters the composition |
| `content` | `() -> Unit` | A `@Composable` function that provides a `DialogScope`. |
