DEV Community

myougaTheAxo
myougaTheAxo

Posted on

DatePicker & TimePicker in Compose: Material3 Date/Time Selection

DatePicker & TimePicker in Compose: Material3 Date/Time Selection

Jetpack Compose Material3 provides elegant date and time selection components that seamlessly integrate into your Android UI. This guide covers the essential patterns for implementing date/time pickers in modern Compose applications.

DatePickerDialog & State Management

The DatePickerDialog composable paired with rememberDatePickerState() provides a controlled approach to date selection:

var showDatePicker by remember { mutableStateOf(false) }
val datePickerState = rememberDatePickerState()

if (showDatePicker) {
    DatePickerDialog(
        onDismissRequest = { showDatePicker = false },
        confirmButton = {
            TextButton(onClick = {
                val selectedDate = datePickerState.selectedDateMillis
                showDatePicker = false
            }) {
                Text("OK")
            }
        }
    ) {
        DatePicker(state = datePickerState)
    }
}

Button(onClick = { showDatePicker = true }) {
    Text("Select Date")
}
Enter fullscreen mode Exit fullscreen mode

SelectableDates for Range Restriction

Control which dates are selectable using the SelectableDates interface:

class DateRangeValidator(
    private val minDateMillis: Long,
    private val maxDateMillis: Long
) : SelectableDates {
    override fun isSelectableDate(utcTimeMillis: Long): Boolean {
        return utcTimeMillis >= minDateMillis && utcTimeMillis <= maxDateMillis
    }

    override fun isSelectableYear(year: Int): Boolean {
        return year >= 2024 && year <= 2026
    }
}

val datePickerState = rememberDatePickerState(
    selectableDates = DateRangeValidator(startMillis, endMillis)
)
Enter fullscreen mode Exit fullscreen mode

DateRangePicker for Range Selection

For selecting a date range, use DateRangePicker:

var showRangePicker by remember { mutableStateOf(false) }
val dateRangePickerState = rememberDateRangePickerState()

if (showRangePicker) {
    DatePickerDialog(
        onDismissRequest = { showRangePicker = false },
        confirmButton = {
            TextButton(onClick = {
                val startDate = dateRangePickerState.selectedStartDateMillis
                val endDate = dateRangePickerState.selectedEndDateMillis
                showRangePicker = false
            }) {
                Text("OK")
            }
        }
    ) {
        DateRangePicker(state = dateRangePickerState)
    }
}
Enter fullscreen mode Exit fullscreen mode

TimePicker: Dial vs Keyboard Input

Material3 offers two time input modes. Choose based on your UX needs:

var selectedTime by remember { mutableStateOf(TimePickerState(10, 30)) }

// Dial input (clock-like interface)
TimePicker(state = selectedTime)

// Keyboard input (manual entry)
// Note: Use TimeInput for keyboard-first experiences
// TimeInput is available via material3-lab extension
Enter fullscreen mode Exit fullscreen mode

Integration with OutlinedTextField

Create a complete date/time picker field:

@Composable
fun DateTimePickerField(
    value: LocalDateTime,
    onValueChange: (LocalDateTime) -> Unit,
    label: String,
    modifier: Modifier = Modifier
) {
    var showPicker by remember { mutableStateOf(false) }
    val datePickerState = rememberDatePickerState(
        initialSelectedDateMillis = value.toMillis()
    )

    OutlinedTextField(
        value = value.format(DateTimeFormatter.ofPattern("MMM dd, yyyy")),
        onValueChange = {},
        label = { Text(label) },
        readOnly = true,
        trailingIcon = {
            IconButton(onClick = { showPicker = true }) {
                Icon(Icons.Default.DateRange, contentDescription = null)
            }
        },
        modifier = modifier
    )

    if (showPicker) {
        DatePickerDialog(
            onDismissRequest = { showPicker = false },
            confirmButton = {
                TextButton(onClick = {
                    datePickerState.selectedDateMillis?.let { mills ->
                        onValueChange(LocalDateTime.ofInstant(
                            Instant.ofEpochMilli(mills),
                            ZoneId.systemDefault()
                        ))
                    }
                    showPicker = false
                }) {
                    Text("OK")
                }
            }
        ) {
            DatePicker(state = datePickerState)
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. State Management: Always use rememberDatePickerState() to preserve state across recompositions
  2. Validation: Implement SelectableDates for business logic constraints
  3. User Feedback: Show selected date/time in the UI immediately
  4. Accessibility: Ensure your picker fields have proper labels and descriptions
  5. Timezone Awareness: Be explicit about timezone handling when converting timestamps

Material3 date/time pickers provide a modern, Material Design-compliant experience that your users expect.


8 Android App Templates → https://myougatheax.gumroad.com

Top comments (0)