A generic, customizable, and multiplatform date and time picker library for Compose Multiplatform. It provides consistent UI components across Android, iOS, Desktop (JVM), and Web (Wasm).
- Multiplatform Support: seamless integration for Android, iOS, Desktop (JVM), and Web (Wasm).
- TimePicker: Supports both 12-hour (AM/PM) and 24-hour formats.
- DatePicker: A complete date picker for selecting year, month, and day with automatic day validation.
- YearMonthPicker: A dedicated component for selecting years and months.
- Customizable: Extensible API with
PickerStyleand display options for reusable UI configuration. - State Management: simplified state handling with
rememberTimePickerState,rememberDatePickerState, andrememberYearMonthPickerState. - Accessibility: Built with accessibility in mind, supporting screen readers and navigation.
The repository includes a Compose Multiplatform sample app with copyable date, time, and bottom sheet flows.
Add the dependency to your version catalog or build file.
[versions]
composeDateTimePicker = "0.4.0"
[libraries]
compose-date-time-picker = { module = "io.github.kez-lab:compose-date-time-picker", version.ref = "composeDateTimePicker" }dependencies {
implementation("io.github.kez-lab:compose-date-time-picker:0.4.0")
}Release status:
0.4.0is the latest public Maven Central/GitHub Releases version. This README is maintained frommainand documents unreleased0.6.0API work, so the Usage and API Reference sections may include APIs that are not available in0.4.0. For published APIs, use the0.4.0release/tag docs. To testmainlocally, run./gradlew :datetimepicker:publishToMavenLocal, addmavenLocal()to your consuming build, and depend on0.6.0.
For release notes and upgrade-impact details, see CHANGELOG.md.
The examples below target the current
mainbranch API. They may require unreleased0.6.0APIs rather than the public0.4.0dependency shown above.
For TimePicker, DatePicker, DateRangePicker, and YearMonthPicker, create the picker state
once with remember*State(...) and pass that same state object to the composable. Inside the picker
UI, that state object is the source of truth for the currently selected value.
- Read the current value from
state.selectedTime,state.selectedDate,state.selectedDateRange, orstate.selectedYearMonth. - Use
onSelected*Changewhen you need to mirror user-driven picker changes into app state, aViewModel, or form data. onSelected*Changeis not called when your app callsstate.select*programmatically. If a button, preset, or external value changes the picker, callstate.select*(...)and update your app-owned value in the same handler.- Do not recreate
remember*Statejust to reset the picker. Keep the state instance and call its publicselect*method.
Use TimePicker for time selection. It supports both 12-hour and 24-hour formats.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.kez.picker.time.TimePicker
import com.kez.picker.time.rememberTimePickerState
import com.kez.picker.util.TimeFormat
import com.kez.picker.util.currentDateTime
@Composable
fun TimePicker24hExample() {
val initialTime = remember { currentDateTime().time }
val state = rememberTimePickerState(
initialTime = initialTime,
timeFormat = TimeFormat.HOUR_24
)
TimePicker(
state = state,
onSelectedTimeChange = { selectedTime ->
// Update app state, ViewModel, or form data here.
}
)
// Use state.selectedTime when passing the result to app logic.
}import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.kez.picker.time.TimePicker
import com.kez.picker.time.rememberTimePickerState
import com.kez.picker.util.TimeFormat
import com.kez.picker.util.currentDateTime
@Composable
fun TimePicker12hExample() {
// Handling of 12-hour format conversion is now done internally by the state
val initialTime = remember { currentDateTime().time }
val state = rememberTimePickerState(
initialTime = initialTime,
timeFormat = TimeFormat.HOUR_12
)
TimePicker(
state = state
)
// state.selectedTime is always a kotlinx.datetime.LocalTime.
}Use PickerDefaults.timePickerItems(minTime = ..., maxTime = ...) when a form should only allow an
inclusive time range. Create state with the same items object so restored or preset values are
coerced before the picker renders.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.kez.picker.PickerDefaults
import com.kez.picker.time.TimePicker
import com.kez.picker.time.rememberTimePickerState
import kotlinx.datetime.LocalTime
@Composable
fun BusinessHoursTimePickerExample() {
val items = remember {
PickerDefaults.timePickerItems(
minuteItems = listOf(0, 15, 30, 45),
minTime = LocalTime(8, 0),
maxTime = LocalTime(18, 0)
)
}
val state = rememberTimePickerState(
items = items,
initialHour = 7,
initialMinute = 30
)
TimePicker(
state = state,
items = items
)
}Use DatePicker for selecting a complete date (year, month, and day). The component automatically
adjusts the day when the selected month changes (e.g., Feb 30 → Feb 28).
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.kez.picker.PickerDefaults
import com.kez.picker.date.DatePicker
import com.kez.picker.date.rememberDatePickerState
import com.kez.picker.util.currentDate
import kotlinx.datetime.LocalDate
import kotlinx.datetime.number
@Composable
fun DatePickerExample() {
val initialDate = remember { currentDate() }
val minDate = remember(initialDate.year) {
LocalDate(initialDate.year, 1, 1)
}
val maxDate = remember(initialDate.year) {
LocalDate(initialDate.year + 1, 12, 31)
}
val selectableYears = remember(minDate.year, maxDate.year) {
(minDate.year..maxDate.year).toList()
}
val selectableDays = remember(initialDate.day) {
listOf(1, 15, initialDate.day).distinct().sorted()
}
val items = remember(selectableYears, selectableDays, minDate, maxDate) {
PickerDefaults.datePickerItems(
yearItems = selectableYears,
dayItems = selectableDays,
minDate = minDate,
maxDate = maxDate
)
}
val state = rememberDatePickerState(
items = items,
initialYear = initialDate.year,
initialMonth = initialDate.month.number,
initialDay = initialDate.day
)
DatePicker(
state = state,
onSelectedDateChange = { selectedDate ->
// Update app state, ViewModel, or form data here.
},
items = items
)
// Use state.selectedDate when passing the result to app logic.
}When you restrict selectable item lists or date bounds with PickerDefaults.*Items(...), keep the
remembered initial or restored state value inside those rules, or create state with
rememberDatePickerState(items = items, initialDate = value) or
rememberDatePickerState(items = items, initialYear = year, initialMonth = month, initialDay = day)
to coerce it before first composition. If an external date changes after composition, call
state.selectDate(newDate, items) or state.selectDate(year, month, day, items) instead of relying
on new initial arguments.
Use DateRangePicker when users need to select an ordered start and end date.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.kez.picker.PickerDefaults
import com.kez.picker.date.DateRange
import com.kez.picker.date.DateRangePicker
import com.kez.picker.date.rememberDateRangePickerState
import com.kez.picker.util.currentDate
import kotlinx.datetime.LocalDate
@Composable
fun DateRangePickerExample() {
val today = remember { currentDate() }
val todayRange = remember(today) {
DateRange(startDate = today, endDate = today)
}
val items = remember(today.year) {
PickerDefaults.datePickerItems(
yearItems = listOf(today.year),
minDate = LocalDate(today.year, 1, 1),
maxDate = LocalDate(today.year, 12, 31)
)
}
val state = rememberDateRangePickerState(
items = items,
initialDateRange = todayRange
)
DateRangePicker(
state = state,
items = items,
onSelectedDateRangeChange = { selectedRange: DateRange ->
// Update app state, ViewModel, or form data here.
}
)
}Use YearMonthPicker for selecting a specific month in a year.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import com.kez.picker.PickerDefaults
import com.kez.picker.date.YearMonth
import com.kez.picker.date.YearMonthPicker
import com.kez.picker.date.rememberYearMonthPickerState
import com.kez.picker.util.currentDate
@Composable
fun YearMonthPickerExample() {
val initialYearMonth = remember { YearMonth.from(currentDate()) }
val minYearMonth = initialYearMonth
val maxYearMonth = remember {
YearMonth(year = initialYearMonth.year + 1, month = initialYearMonth.month)
}
val items = remember {
PickerDefaults.yearMonthPickerItems(
minYearMonth = minYearMonth,
maxYearMonth = maxYearMonth
)
}
val state = rememberYearMonthPickerState(
items = items,
initialYearMonth = initialYearMonth
)
YearMonthPicker(
state = state,
items = items,
onSelectedYearMonthChange = { selectedYearMonth: YearMonth ->
// Update app state, ViewModel, or form data here.
}
)
// state.selectedYearMonth is YearMonth(year, month).
// state.selectedMonthDate is still available for LocalDate interoperability.
}The pickers work seamlessly within a ModalBottomSheet or other dialog components. Keep the
committed value separate from the temporary sheet state so dismissing the sheet does not accidentally
change app state.
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.Text
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.kez.picker.time.rememberTimePickerState
import com.kez.picker.time.TimePicker
import kotlinx.datetime.LocalTime
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun BottomSheetPickerExample() {
var committedHour by rememberSaveable { mutableIntStateOf(9) }
var committedMinute by rememberSaveable { mutableIntStateOf(30) }
var showBottomSheet by remember { mutableStateOf(false) }
val sheetState = rememberModalBottomSheetState()
val committedTime = LocalTime(committedHour, committedMinute)
Column(verticalArrangement = Arrangement.spacedBy(12.dp)) {
Text("Selected time: $committedTime")
Button(onClick = { showBottomSheet = true }) {
Text("Select Time")
}
}
if (showBottomSheet) {
val draftState = rememberTimePickerState(initialTime = committedTime)
ModalBottomSheet(
onDismissRequest = { showBottomSheet = false },
sheetState = sheetState
) {
Column(
modifier = Modifier
.fillMaxWidth()
.padding(24.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
TimePicker(state = draftState)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
OutlinedButton(
onClick = { showBottomSheet = false },
modifier = Modifier.weight(1f)
) {
Text("Cancel")
}
Button(
onClick = {
val selected = draftState.selectedTime
committedHour = selected.hour
committedMinute = selected.minute
showBottomSheet = false
},
modifier = Modifier.weight(1f)
) {
Text("Apply")
}
}
}
}
}
}The example stores hour and minute separately because primitive values work with rememberSaveable;
LocalTime is recreated as a derived value before creating the draft picker state.
This reference describes the current
mainbranch API. Check CHANGELOG.md and the0.4.0release/tag docs before copying API examples into a project that depends on the public0.4.0artifact.
Public state APIs live beside their components: TimePicker, TimePickerState, and
rememberTimePickerState are in com.kez.picker.time; DatePicker, DatePickerState,
YearMonthPicker, YearMonthPickerState, and their remember*State functions are in
com.kez.picker.date.
Accessibility options customize the picker-column prefix, accessibility value text, and previous/next
accessibility action labels without changing the visual item text. Selection is exposed through Compose
selected semantics rather than appended as a hardcoded English phrase. Use
PickerDefaults.accessibility(...), timePickerAccessibility(...), datePickerAccessibility(...), or
yearMonthPickerAccessibility(...) to create reusable localized accessibility objects.
Display options customize the visible item text without changing accessibility output. Use
PickerDefaults.itemText(...) on a generic Picker<T>, or PickerDefaults.timePickerDisplay(...),
datePickerDisplay(...), and yearMonthPickerDisplay(...) for composite pickers when visible labels
need padding, suffixes, or localized month/period names.
TimePicker(
state = state,
display = PickerDefaults.timePickerDisplay(
hourItemText = { it.toString().padStart(2, '0') },
minuteItemText = { it.toString().padStart(2, '0') }
),
accessibility = PickerDefaults.timePickerAccessibility(
hourPickerLabel = "Hour",
minutePickerLabel = "Minute",
hourItemContentDescription = { "$it hour" },
minuteItemContentDescription = { "$it minute" },
previousItemActionLabel = "Select previous value",
nextItemActionLabel = "Select next value"
)
)Use Picker<T> when you need a single custom picker column.
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.rememberSaveable
import androidx.compose.runtime.setValue
import com.kez.picker.Picker
import com.kez.picker.PickerDefaults
@Composable
fun SizePickerExample() {
val items = listOf("Small", "Medium", "Large")
var selectedSize by rememberSaveable { mutableStateOf("Medium") }
Picker(
items = items,
selectedItem = selectedSize,
onSelectedItemChange = { selectedSize = it },
enabled = true,
isInfinity = false,
display = PickerDefaults.itemText(
itemText = { size -> size.uppercase() }
),
accessibility = PickerDefaults.accessibility(
pickerLabel = "Size",
itemContentDescription = { it }
)
)
}Picker<T> is a controlled component. Keep the selected value in app state, pass it through
selectedItem, and update that state from onSelectedItemChange. items must be non-empty and
distinct, and selectedItem must exist in items. If T is not saveable, store a saveable key in
your app state and map that key back to an item before rendering the picker.
Pass enabled = false to prevent user scroll, click, and accessibility selection actions while still
showing the current value. Disabled pickers use the disabled slots from PickerDefaults.colors(...)
for default text, dividers, and selected-item backgrounds.
Custom content receives PickerItemScope<T> so custom rows can reuse the default formatted text,
selected/enabled state, distance fraction, text style, and content color:
Picker(
items = items,
selectedItem = selectedSize,
onSelectedItemChange = { selectedSize = it },
content = { item ->
Text(
text = if (item.isSelected) "[${item.text}]" else item.text,
style = item.textStyle,
color = item.contentColor
)
}
)Use style = PickerDefaults.style(...) to customize visible item count, colors, text styles,
dividers, item padding, selected item background, and fading edge behavior with one reusable object.
Use display.itemText for visible text and accessibility.itemContentDescription for screen-reader
text when those two strings should differ.
Create picker state with remember*State, pass it to the picker, then call the public selection method
from an event handler or a LaunchedEffect(externalValue). Do not recreate the state just to reset the
selection.
| State | Method |
|---|---|
Generic Picker<T> |
Update the app-owned selectedItem value |
time.TimePickerState |
selectTime(LocalTime(...)), selectTime(hour, minute), or the matching items overloads |
date.DatePickerState |
selectDate(LocalDate(...)), selectDate(year, month, day), or the matching items overloads |
date.DateRangePickerState |
selectDateRange(DateRange(...)), selectDateRange(startDate, endDate), selectDateRange(startYear, startMonth, startDay, endYear, endMonth, endDay), selectStartDate(...), selectEndDate(...), or the matching items overloads |
date.YearMonthPickerState |
selectYearMonth(YearMonth(...)), selectYearMonth(year, month), selectDate(LocalDate(...)), or the matching items overloads |
import androidx.compose.foundation.layout.Column
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import com.kez.picker.time.rememberTimePickerState
import com.kez.picker.time.TimePicker
import kotlinx.datetime.LocalTime
@Composable
fun ProgrammaticTimePickerExample() {
val state = rememberTimePickerState(initialTime = LocalTime(8, 0))
Column {
Button(onClick = { state.selectTime(hour = 9, minute = 30) }) {
Text("Set 09:30")
}
TimePicker(state = state)
}
}The picker scroll position is synchronized when the current item lists contain the requested values. Custom
item lists are strict: they must be non-empty, distinct, within the supported value ranges, and contain the
current selected value. TimePicker filters hour, minute, and AM/PM columns through optional
minTime/maxTime bounds. DatePicker filters dayItems by the selected year/month maximum day and
optional minDate/maxDate bounds. If an app can restore or request values outside a custom list or
configured bounds, call items.contains(...) to check primitive or value objects before rejecting a
value, or call the state.select*(value, items) overload or items.coerce* helper to move to the
closest selectable value before rendering the picker.
For first composition, use remember*State(items = items, initial... = value) to apply the same coercion
before the picker is rendered.
onSelectedTimeChange, onSelectedDateChange, onSelectedDateRangeChange, and
onSelectedYearMonthChange are called for user-driven picker changes. Programmatic state.select*
calls update the state directly; update your app-owned value in the same event handler when you
trigger programmatic changes.
Use PickerDefaults.timePickerLayout(...), datePickerLayout(...), or yearMonthPickerLayout(...)
when a composite picker needs different column proportions. Pass null for a column weight to let
pickerModifier provide an explicit width for that column. Use columnOrder when locale, product,
or form conventions need a different order, such as month/day/year:
DatePicker(
state = state,
layout = PickerDefaults.datePickerLayout(
columnOrder = listOf(
DatePickerColumn.MONTH,
DatePickerColumn.DAY,
DatePickerColumn.YEAR
)
)
)columnOrder must contain each column exactly once. For TimePicker, TimePickerColumn.PERIOD
is rendered only in 12-hour mode and ignored in 24-hour mode.
| Parameter | Description | Default |
|---|---|---|
state |
The state object to control the picker. | rememberTimePickerState() |
onSelectedTimeChange |
Called after user interaction changes the selected LocalTime. |
{} |
enabled |
Whether user scroll, click, and accessibility selection actions are enabled. | true |
items |
Selectable minute, 24-hour hour, 12-hour display-hour, and AM/PM item lists plus optional inclusive minTime/maxTime bounds. |
PickerDefaults.timePickerItems() |
display |
Visible item text formatters for each picker column. | PickerDefaults.timePickerDisplay() |
style |
Visual and layout styling for each picker column. | PickerDefaults.style() |
layout |
Column weights and visual order for period, hour, and minute picker columns. Use null weights for explicit-width columns. |
PickerDefaults.timePickerLayout() |
spacingBetweenPickers |
Horizontal spacing between picker columns. | 0.dp |
accessibility |
Accessibility labels, item descriptions, and custom action labels for each picker column. | PickerDefaults.timePickerAccessibility() |
TimePickerState Properties:
selectedHour: The selected hour shown by the picker.selectedMinute: The selected minute (0-59).selectedPeriod: The selected AM/PM period when using 12-hour format.selectedHourOfDay: The selected hour converted to 24-hour clock time (0-23).selectedTime: The selected value askotlinx.datetime.LocalTime.
rememberTimePickerState uses saveable state. On Android, selected values can be restored across Activity recreation when the platform saveable registry is available.
For initial values, use either rememberTimePickerState(initialTime = LocalTime(...)) or the
explicit initialHour/initialMinute parameters. Pass the same items object when the initial time
or parts should be coerced before first composition.
To change the selection after state creation, call state.selectTime(LocalTime(...)) or
state.selectTime(hour, minute). Use the overloads that accept items when custom item lists or
time bounds should be applied at the same time. The integer hour is interpreted as hour-of-day in
0..23.
Invalid custom item values, duplicate items, empty required lists, or current selections missing from custom lists or time bounds throw IllegalArgumentException during composition. In 12-hour mode, PickerDefaults.timePickerItems(hour12Items = ...) uses display-hour values (1..12): initialHour = 13 becomes state.selectedHour == 1 with PM.
| Parameter | Description | Default |
|---|---|---|
state |
The state object to control the picker. | rememberDatePickerState() |
onSelectedDateChange |
Called after user interaction changes the selected LocalDate. |
{} |
enabled |
Whether user scroll, click, and accessibility selection actions are enabled. | true |
items |
Selectable year/month/day item lists plus optional inclusive minDate/maxDate bounds. Values must be in 1000..9999, 1..12, and 1..31. |
PickerDefaults.datePickerItems() |
display |
Visible item text formatters for each picker column. | PickerDefaults.datePickerDisplay() |
style |
Visual and layout styling for each picker column. | PickerDefaults.style() |
layout |
Column weights and visual order for year, month, and day picker columns. Use null weights for explicit-width columns. |
PickerDefaults.datePickerLayout() |
spacingBetweenPickers |
Horizontal spacing between picker columns. | 0.dp |
accessibility |
Accessibility labels, item descriptions, and custom action labels for each picker column. | PickerDefaults.datePickerAccessibility() |
DatePickerState Properties:
selectedYear: The currently selected year.selectedMonth: The currently selected month (1-12).selectedDay: The currently selected day (1-31, auto-adjusted based on month).selectedDate: The selected value askotlinx.datetime.LocalDate.maxDay: The maximum valid day for the selected year and month.
rememberDatePickerState uses saveable state. On Android, selected values can be restored across Activity recreation when the platform saveable registry is available.
For initial values, use either rememberDatePickerState(initialDate = LocalDate(...)) or the
explicit initialYear/initialMonth/initialDay parameters. Pass the same items object when the
initial value or parts should be coerced before first composition. Initial years must be in
1000..9999, months in 1..12, and days must be at least 1. If initialDay is greater than the
maximum valid day for the initial year/month, it is clamped to that maximum.
To change the selection after state creation, call state.selectDate(LocalDate(...)) or
state.selectDate(year, month, day). Use the overloads that accept items when custom item lists
or date bounds should be applied at the same time.
Invalid custom item values, duplicate items, empty lists, or current selected year/month/day values missing from custom lists or date bounds throw IllegalArgumentException during composition. If a year/month change makes the selected month or day unavailable, the picker selects the closest available value for the configured constraints.
| Parameter | Description | Default |
|---|---|---|
state |
The state object to control the selected start and end dates. | rememberDateRangePickerState() |
onSelectedDateRangeChange |
Called after user interaction changes the selected DateRange. |
{} |
enabled |
Whether user scroll, click, and accessibility selection actions are enabled. | true |
items |
Shared selectable year/month/day item lists plus optional inclusive minDate/maxDate bounds. |
PickerDefaults.datePickerItems() |
display |
Visible item text formatters for each picker column. | PickerDefaults.datePickerDisplay() |
style |
Visual and layout styling for each picker column. | PickerDefaults.style() |
layout |
Column weights and visual order for each child DatePicker. |
PickerDefaults.datePickerLayout() |
spacingBetweenPickers |
Horizontal spacing between columns inside each child DatePicker. |
0.dp |
spacingBetweenDatePickers |
Vertical spacing between the start and end child pickers. | 16.dp |
startLabel / endLabel |
Optional visible labels above each child picker. | "Start date" / "End date" |
accessibility |
Accessibility labels for the start and end child pickers. | PickerDefaults.dateRangePickerAccessibility() |
DateRangePickerState keeps selectedStartDate <= selectedEndDate. If a user moves the start after
the current end, the end moves to the same date. If a user moves the end before the current start,
the start moves to the same date.
For initial values, use rememberDateRangePickerState(initialDateRange = DateRange(...)),
rememberDateRangePickerState(initialStartDate = ..., initialEndDate = ...), or the explicit
initialStartYear/initialStartMonth/initialStartDay and matching end-date parameters. To change
the selection after state creation, call state.selectDateRange(...), state.selectStartDate(...),
or state.selectEndDate(...) with DateRange, LocalDate, or explicit year/month/day values.
DateRange can also be created from explicit start/end year, month, and day parts. If app-owned
start/end fields may be entered in either order, use DateRange.ordered(startDate, endDate) or the
matching year/month/day overload before passing the value to state. Use range.contains(year, month, day) when app-owned form fields need an inclusive range check before creating a LocalDate.
| Parameter | Description | Default |
|---|---|---|
state |
The state object to control the picker. | rememberYearMonthPickerState() |
onSelectedYearMonthChange |
Called after user interaction changes the selected YearMonth. |
{} |
enabled |
Whether user scroll, click, and accessibility selection actions are enabled. | true |
items |
Selectable year/month item lists plus optional inclusive minYearMonth/maxYearMonth bounds. Values must be in 1000..9999 and 1..12. |
PickerDefaults.yearMonthPickerItems() |
display |
Visible item text formatters for each picker column. | PickerDefaults.yearMonthPickerDisplay() |
style |
Visual and layout styling for each picker column. | PickerDefaults.style() |
layout |
Column weights and visual order for year and month picker columns. Use null weights for explicit-width columns. |
PickerDefaults.yearMonthPickerLayout() |
spacingBetweenPickers |
Horizontal spacing between picker columns. | 0.dp |
accessibility |
Accessibility labels, item descriptions, and custom action labels for each picker column. | PickerDefaults.yearMonthPickerAccessibility() |
YearMonthPickerState Properties:
selectedYear: The currently selected year.selectedMonth: The currently selected month (1-12).selectedYearMonth: The selected value asdate.YearMonth.selectedMonthDate: The selected year/month represented as the first day of that month.
rememberYearMonthPickerState uses saveable state. On Android, selected values can be restored across Activity recreation when the platform saveable registry is available.
For initial values, prefer rememberYearMonthPickerState(initialYearMonth = YearMonth(...)) for year/month-only selections. You can also initialize from initialDate = LocalDate(...) for date interop, or use the explicit initialYear/initialMonth parameters. Initial years must be in 1000..9999.
To change the selection after state creation, call state.selectYearMonth(YearMonth(...)),
state.selectYearMonth(year, month), or state.selectDate(LocalDate(...)).
Invalid custom item values, duplicate items, empty lists, or current selected year/month values missing from custom lists or year/month bounds throw IllegalArgumentException during composition. If a year change makes the current month unavailable, the picker moves to the closest available YearMonth.
Copyright 2024 KEZ Lab
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.



