[ Web Proxy ]
URL:
Viewing: https://developer.android.com/develop/ui/compose/components/datepickers [Back]  [Original]

Date pickers  |  Jetpack Compose  |  Android Developers Skip to main content
Essentials Design & Plan Develop Google Play Blog
Search:
Android Studio
Android Developers [Android Developers]

Date pickers Stay organized with collections Save and categorize content based on your preferences.

Date pickers let users select a date, a date range, or both. They use a calendar dialog or text input to let users select dates.

Types

There are three types of date pickers:

You can implement these date pickers in your app using the following composables:

Note: DatePicker, DatePickerDialog, and DateRangePicker are experimental. File any issues on the issue tracker.

State

The key parameter that the different date picker composables share in common is state, which takes either a DatePickerState or DateRangePickerState object. Their properties capture information about the user's selection using the date picker, such as the current selected date.

For more information on how you can make use of the selected date, see the Use selected date section.

Docked date picker

In the following example, there is a text field that prompts the user to input their date of birth. When they click the calendar icon in the field, it opens a docked date picker below the input field.

@Composable
fun DatePickerDocked() {
    var showDatePicker by remember { mutableStateOf(false) }
    val datePickerState = rememberDatePickerState()
    val selectedDate = datePickerState.selectedDateMillis?.let {
        convertMillisToDate(it)
    } ?: ""

    Box(
        modifier = Modifier.fillMaxWidth()
    ) {
        OutlinedTextField(
            value = selectedDate,
            onValueChange = { },
            label = { Text("DOB") },
            readOnly = true,
            trailingIcon = {
                IconButton(onClick = { showDatePicker = !showDatePicker }) {
                    Icon(
                        imageVector = Icons.Default.DateRange,
                        contentDescription = "Select date"
                    )
                }
            },
            modifier = Modifier
                .fillMaxWidth()
                .height(64.dp)
        )

        if (showDatePicker) {
            Popup(
                onDismissRequest = { showDatePicker = false },
                alignment = Alignment.TopStart
            ) {
                Box(
                    modifier = Modifier
                        .fillMaxWidth()
                        .offset(y = 64.dp)
                        .shadow(elevation = 4.dp)
                        .background(MaterialTheme.colorScheme.surface)
                        .padding(16.dp)
                ) {
                    DatePicker(
                        state = datePickerState,
                        showModeToggle = false
                    )
                }
            }
        }
    }
}

@Composable
fun DatePickerFieldToModal(modifier: Modifier = Modifier) {
    var selectedDate by remember { mutableStateOf<Long?>(null) }
    var showModal by remember { mutableStateOf(false) }

    OutlinedTextField(
        value = selectedDate?.let { convertMillisToDate(it) } ?: "",
        onValueChange = { },
        label = { Text("DOB") },
        placeholder = { Text("MM/DD/YYYY") },
        trailingIcon = {
            Icon(Icons.Default.DateRange, contentDescription = "Select date")
        },
        modifier = modifier
            .fillMaxWidth()
            .pointerInput(selectedDate) {
                awaitEachGesture {
                    // Modifier.clickable doesn't work for text fields, so we use Modifier.pointerInput
                    // in the Initial pass to observe events before the text field consumes them
                    // in the Main pass.
                    awaitFirstDown(pass = PointerEventPass.Initial)
                    val upEvent = waitForUpOrCancellation(pass = PointerEventPass.Initial)
                    if (upEvent != null) {
                        showModal = true
                    }
                }
            }
    )

    if (showModal) {
        DatePickerModal(
            onDateSelected = { selectedDate = it },
            onDismiss = { showModal = false }
        )
    }
}

fun convertMillisToDate(millis: Long): String {
    val formatter = SimpleDateFormat("MM/dd/yyyy", Locale.getDefault())
    return formatter.format(Date(millis))
}

Note: This example is self-contained. For how you can expose the selected date to a parent composable, see the other examples.

Key points about the code

Results

After clicking the calendar icon, this implementation appears as follows:

Docked date picker example. [Docked date picker example.] Figure 1. A docked date picker.

A modal date picker displays a dialog that floats over the screen. To implement it, create a DatePickerDialog and pass it a DatePicker.

@Composable
fun DatePickerModal(
    onDateSelected: (Long?) -> Unit,
    onDismiss: () -> Unit
) {
    val datePickerState = rememberDatePickerState()

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(onClick = {
                onDateSelected(datePickerState.selectedDateMillis)
                onDismiss()
            }) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
}

Results

This implementation appears as follows:

Modal date picker example. [Modal date picker example.] Figure 2. A modal date picker.

Input modal date picker

A modal date picker with input displays a dialog that floats over the screen and allows the user to input a date.

@Composable
fun DatePickerModalInput(
    onDateSelected: (Long?) -> Unit,
    onDismiss: () -> Unit
) {
    val datePickerState = rememberDatePickerState(initialDisplayMode = DisplayMode.Input)

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(onClick = {
                onDateSelected(datePickerState.selectedDateMillis)
                onDismiss()
            }) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
}

This is very much the same as the modal date picker example. The primary difference is the following:

Modal date picker with input. [Modal date picker with input.] Figure 3. A modal date picker with input.

Date picker with range

You can create a date picker that lets the user select a range between a start and end date. To do so, use DateRangePicker.

The use of DateRangePicker is essentially the same as DatePicker. You can use it for a docked picker as a child of PopUp, or you can use it as a modal picker and pass it to DatePickerDialog. The primary difference is that you use DateRangePickerState instead of DatePickerState.

The following snippet demonstrates how to create a modal date picker with a range:

@Composable
fun DateRangePickerModal(
    onDateRangeSelected: (Pair<Long?, Long?>) -> Unit,
    onDismiss: () -> Unit
) {
    val dateRangePickerState = rememberDateRangePickerState()

    DatePickerDialog(
        onDismissRequest = onDismiss,
        confirmButton = {
            TextButton(
                onClick = {
                    onDateRangeSelected(
                        Pair(
                            dateRangePickerState.selectedStartDateMillis,
                            dateRangePickerState.selectedEndDateMillis
                        )
                    )
                    onDismiss()
                }
            ) {
                Text("OK")
            }
        },
        dismissButton = {
            TextButton(onClick = onDismiss) {
                Text("Cancel")
            }
        }
    ) {
        DateRangePicker(
            state = dateRangePickerState,
            title = {
                Text(
                    text = "Select date range"
                )
            },
            showModeToggle = false,
            modifier = Modifier
                .fillMaxWidth()
                .height(500.dp)
                .padding(16.dp)
        )
    }
}

Key points about the code

Results

This implementation appears as follows:

Modal range date picker example. [Modal range date picker example.] Figure 4. A modal date picker with a selected range.

Use selected date

To capture the selected date, track it in the parent composable as a Long and pass the value to the DatePicker in onDateSelected. The following snippet demonstrates this, though you can see the full implementation in the official snippets app.

// ...
    var selectedDate by remember { mutableStateOf<Long?>(null) }
// ...
        if (selectedDate != null) {
            val date = Date(selectedDate!!)
            val formattedDate = SimpleDateFormat("MMM dd, yyyy", LocalLocale.current.platformLocale).format(date)
            Text("Selected date: $formattedDate")
        } else {
            Text("No date selected")
        }
// ...
        DatePickerModal(
            onDateSelected = {
                selectedDate = it
                showModal = false
            },
            onDismiss = { showModal = false }
        )
    }
// ...

Essentially the same applies for range date pickers, though you need to use a Pair<Long?, Long?> or a data class to capture the start and end values.

Important: Instead of using a Long for the selected date, you could pass the state object itself from the parent composable to the child. Doing so would let you capture the full state in the parent.

See also

Content and code samples on this page are subject to the licenses described in the Content License. Java and OpenJDK are trademarks or registered trademarks of Oracle and/or its affiliates.

Last updated 2026-08-14 UTC.

[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2026-08-14 UTC."],[],[]]

Web Proxy Viewer  |  New URL  |  Original Page