Compose DatePicker BottomSheet is a powerful, flexible, and beautifully designed component for selecting Persian (Jalali) dates. Built on Jetpack Compose, it provides a smooth and professional experience for date selection in Persian apps.
- ✅ Full Persian calendar support, fully compatible with Jetpack Compose
- 🌐 Complete Persian language support (days, months, numbers)
- 📅 Date output in both Persian (Jalali) and Gregorian formats
- 🖋️ Custom Persian fonts with multiple weights
- ⚙️ Optimized architecture, ready to use in Compose-based projects
- 📆 Support for selecting only month and year without requiring a day selection (ideal for use cases where day selection is unnecessary)
- 🎨 Fully customizable UI: colors, fonts, sizes, and layout
- 📅 Ability to provide an initial default date to be pre-selected when opening the Persian date picker, useful for cases where the user has previously selected a date and now needs to edit it.
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
mavenCentral()
maven { url = uri("https://jitpack.io") }
}
}
dependencies {
implementation("com.github.MohammadSadeghMehrafzoon:ComposeDatePicker:V1.1.3")
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun DatePickerModalBottomSheet() {
val datePickerController = rememberDialogDatePicker()
val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)
val coroutine = rememberCoroutineScope()
var persianFullDate by remember { mutableStateOf("") }
var gregorianDate by remember { mutableStateOf("") }
var persianMonth by remember { mutableStateOf("") }
var timestamp by remember { mutableStateOf("") }
var fullDate by remember { mutableStateOf("") }
var persianMonthNameAndPersianYear by remember { mutableStateOf("") }
var getMiladiFullDate by remember { mutableStateOf("") }
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text("با کلیک بر روی دکمه زیر تاریخ مورد نظر خود را انتخاب کنید")
Spacer(Modifier.height(10.dp))
Button(
onClick = {
coroutine.launch { bottomSheetState.show() }
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Unspecified),
shape = RoundedCornerShape(10.dp),
) {
Text(
text = "انتخاب تاریخ",
textAlign = TextAlign.Center,
)
}
Spacer(Modifier.height(20.dp))
Text(persianFullDate)
Text(gregorianDate)
Text(persianMonth)
Text(fullDate)
Text(persianMonthNameAndPersianYear)
Text(getMiladiFullDate)
if (timestamp.isNotEmpty()){
Text("timestamp $timestamp")
}
}
if (bottomSheetState.isVisible) {
DatePickerModalBottomSheet(
modifier = Modifier
.fillMaxWidth()
.wrapContentHeight(),
onSubmitClick = {
persianFullDate = datePickerController.getPersianFullDate()
gregorianDate = datePickerController.getGregorianDate().toString()
persianMonth = datePickerController.getPersianMonth().toString()
timestamp = datePickerController.getTimestamp().toString()
fullDate = datePickerController.getFullDate()
persianMonthNameAndPersianYear = datePickerController.getPersianMonthNameAndPersianYear()
getMiladiFullDate = datePickerController.getMiladiFullDate()
},
sheetState = bottomSheetState,
controller = datePickerController,
onDismissRequest = {
coroutine.launch { bottomSheetState.hide() }
},
font = RegularFont,
textButtonStyle = TextStyle(fontFamily = FontFamily(Font(BoldFont))),
//useInitialDate = true,
//initialDate = Triple(1404,6,27)
//datePickerWithoutDay = true
//titleStyle = TextStyle(fontFamily = FontFamily(Font(MediumFont))),
//titleBottomSheet = "تاریخ مورد نظر خود را انتخاب کنید",
//titleModifier = Modifier.padding(start = 10.dp)
)
}
}
🔧 Function | 📝 Description |
---|---|
getPersianYear(): Int |
Returns the Persian year (e.g., 1403 ) |
getPersianMonth(): Int |
Returns the Persian month number from 1 to 12 (e.g., 3 for Khordad) |
getPersianDay(): Int |
Returns the Persian day of the month from 1 to 31 (e.g., 19 ) |
getPersianMonthName(): String |
Returns the Persian month name (e.g., "خرداد" ) |
getPersianDayOfWeekName(): String |
Returns the Persian day of the week name (e.g., "چهارشنبه" ) |
🔧 Function | 📝 Description |
---|---|
getGregorianYear(): Int |
Returns the Gregorian year (e.g., 2025 ) |
getGregorianMonth(): Int |
Returns the Gregorian month number from 1 to 12 (e.g., 6 for June) |
getGregorianDay(): Int |
Returns the Gregorian day of the month (e.g., 11 ) |
getGregorianDate(): Date |
Returns the full Gregorian date as a Date object |
🔧 Function | 📝 Description |
---|---|
getDayOfWeek(): Int |
Returns the day of the week number (the meaning of the number may vary depending on the implementation) |
🔧 Function | 📝 Description |
---|---|
getFullDate(): String |
Returns the full Persian date in yyyy/MM/dd format (e.g., "1403/03/19" ) |
getPersianMonthNameAndPersianYear(): String |
Returns a combination of Persian month name and year (e.g., "خرداد 1403" ) |
getMiladiFullDate(): String |
Returns the full Gregorian date in yyyy/MM/dd format (e.g., "2025/06/11" ) |
getPersianFullDate(): String |
Returns the detailed Persian date (e.g., "چهارشنبه 19 خرداد 1403" ) |
🔧 Function | 📝 Description |
---|---|
getTimestamp(): Long |
Returns the Unix timestamp (number of milliseconds since 1970-01-01 ) for the current date |
Font Variable | Font Weight | Usage Description |
---|---|---|
BoldFont |
Bold (700) | Suitable for titles and highly emphasized sections |
MediumFont |
Medium (500) | Ideal for buttons or semi-bold texts |
RegularFont |
Regular (400) | Used for general body text and main content |
LightFont |
Light (300) | Suitable for secondary or descriptive texts |
ThinFont |
Thin (200) | Suitable for very light and delicate text |
HairlineFont |
Hairline (100) | The thinnest font weight, ideal for decorative or neutral text |
Parameter | Type / Description |
---|---|
modifier |
Modifier — Used to configure the overall layout of the Bottom Sheet. |
titleModifier |
Modifier — Modifier for the top title inside the Bottom Sheet. |
sheetState |
SheetState — Current state of the Bottom Sheet. Use rememberModalBottomSheetState() to create it. |
controller |
✅ Required — Controller for the selected date. Must be created and remembered inside a composable. |
submitTitle |
String — Text for the confirm button (default: "تایید" / "Confirm" ) |
titleBottomSheet |
String — Title displayed at the top of the Bottom Sheet. |
titleStyle |
TextStyle — Style for the title text (font, size, color, etc.). |
textButtonStyle |
TextStyle — Style for the confirm button text. |
unSelectedStyle |
TextStyle? — Style for unselected date items (optional). |
selectedStyle |
TextStyle? — Style for the selected date item (optional). |
buttonColor |
Color — Background color of the confirm button. |
containerColor |
Color — Background color of the Bottom Sheet. |
lineColor |
Color — Color of the divider lines inside the picker. |
shape |
Shape — Shape of the Bottom Sheet corners. |
font |
Int? — Custom font ID. |
onDateChanged |
(year: Int, month: Int, day: Int) -> Unit — Callback triggered when the selected date changes. |
properties |
ModalBottomSheetProperties — Advanced Bottom Sheet behavior configuration. |
onDismissRequest |
✅ Required — Callback triggered when the sheet is dismissed (e.g., drag down or tap outside). |
onSubmitClick |
✅ Required — Callback triggered when the confirm button is clicked. |
datePickerWithoutDay |
Boolean — Enables month/year only selection mode and hides the day selector. |
useInitialDate |
Boolean — A boolean flag indicating whether to use a predefined date. |
initialDate |
Triple — A Triple<Int, Int, Int> representing the year, month, and day in the Persian calendar. Sample: Triple(1404,6,27) . |