DatePicker & TimePicker in Compose: Material3 Date/Time Selection
Source: Dev.to
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")
}
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 = 2024 && year Unit,
}
}
Example: Custom DatePickerField
Below is an example of a reusable composable that integrates a DatePickerDialog with an OutlinedTextField:
@Composable
fun DatePickerField(
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)
}
}
}
Best Practices
- State Management: Always use
rememberDatePickerState()to preserve state across recompositions. - Validation: Implement
SelectableDatesfor business‑logic constraints. - User Feedback: Show the selected date/time in the UI immediately.
- Accessibility: Ensure picker fields have proper labels and content descriptions.
- 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.