persian_calendar_widget 0.7.0
persian_calendar_widget: ^0.7.0 copied to clipboard
Pick a date with a custom dialog box in Persian calendar that can be used in any project.
persian_calendar_widget #
A Flutter package that provides a customizable grid view calendar widget and date picker by supporting Persian (Jalali) and Gregorian calendars, with internationalization (i18n) support.

Live Demo #
If you want to see the demo web app, visit: https://persian-calendar-demo.web.app
Example App #
Check the full example here: https://github.com/Persian-Widgets/persian_calendar_demo_app
Features #
- Supports both Persian (Jalali) and Gregorian calendars.
- Embeddable
GridViewCalendarfor custom inline calendars with powerful builder callbacks for day and weekday tiles. - Two widget variants:
MinimalPersianCalendar(simple styling) andCustomDecorationPersianCalendar(full customization). - Flexible date picking modes: full date (day/month/year), month/day, day only, or year/month.
- Internationalization for buttons, weekdays, and months.
- Optional Persian digits display.
- Customizable first day of the week (Saturday, Sunday, or Monday).
- Today banner and "Go to Today" button.
- Full theming support via TextStyle (Minimal) or BoxDecoration/ButtonStyle (Custom).
Usage #
The package provides two main classes: MinimalPersianCalendar for basic styling and CustomDecorationPersianCalendar for advanced customization. Both offer static methods to show date picker dialogs:
pickFullDate: Select day, month, and year.pickMonthAndDay: Select month and day (no year).pickDay: Select day only (fixed month/year).pickYearAndMonth: Select year and month (no day).
Additionally, GridViewCalendar provides a non-dialog widget for embedding a customizable grid-based calendar view directly in your UI, ideal for inline date selection, event calendars, or multi-month layouts. It uses builder callbacks to empower developers with full control over rendering each day and weekday, enabling features like event indicators, custom colors, or interactive elements.
The onSubmit callback receives:
selectedDate: Record withjalali: Jalaliandgregorian: Gregorianobjects.formattedDate: Record withjalali: Stringandgregorian: String(e.g., "12 Ordibehesht 1403").
GridViewCalendar #
GridViewCalendar is a powerful, embeddable widget that renders a month's days in a 7-column grid. Developers can customize each day tile via DayTileBuilder (receiving Jalali and Gregorian dates) and weekday headers via WeekDayTileBuilder. This allows for highly flexible implementations, such as highlighting specific dates, adding event badges, or creating swipeable multi-month calendars. It supports both calendar types, custom starting days, i18n, and layout adjustments for seamless integration into any Flutter UI.
Usage Example
import 'package:flutter/material.dart';
import 'package:persian_calendar_widget/persian_calendar_widget.dart';
class MyCalendar extends StatefulWidget {
@override
_MyCalendarState createState() => _MyCalendarState();
}
class _MyCalendarState extends State<MyCalendar> {
DateTime? selectedDate;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Grid Calendar')),
body: Padding(
padding: const EdgeInsets.all(16.0),
child: GridViewCalendar(
calendarType: CalendarType.jalali,
initDate: (year: 1403, month: 2), // Ordibehesht 1403
firstDayOfWeek: FirstDayOfWeek.saturday,
i18n: I18n(), // Customize if needed
// Custom weekday header builder
weekDayTileBuilder: (weekDay) => Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: Colors.blue.shade50,
borderRadius: BorderRadius.circular(4),
),
child: Text(
weekDay,
style: const TextStyle(fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
),
// Custom day tile builder with selection
builder: (jalaliDate, gregorianDate) {
final isSelected = selectedDate == gregorianDate.toDateTime();
final isToday = gregorianDate.toDateTime().isToday;
return GestureDetector(
onTap: () => setState(() {
selectedDate = gregorianDate.toDateTime();
}),
child: Container(
margin: const EdgeInsets.all(2),
decoration: BoxDecoration(
color: isSelected
? Colors.blue
: (isToday ? Colors.green.shade100 : null),
borderRadius: BorderRadius.circular(4),
border: Border.all(
color: isSelected ? Colors.blue : Colors.grey.shade300,
),
),
child: Center(
child: Text(
jalaliDate.formatter.dd.toString(),
style: TextStyle(
color: isSelected ? Colors.white : Colors.black87,
fontWeight: isSelected ? FontWeight.bold : FontWeight.normal,
),
),
),
),
);
},
mainAxisExtent: 50, // Height of each day tile
crossAxisSpacing: 4,
mainAxisSpacing: 4,
padding: const EdgeInsets.symmetric(horizontal: 4),
),
),
);
}
}
This example demonstrates selecting dates via taps and custom styling for selected/today states, showcasing the widget's flexibility for interactive calendars.
MinimalPersianCalendar.pickFullDate #
import 'package:flutter/material.dart';
import 'package:persian_calendar_widget/persian_calendar_widget.dart';
ElevatedButton(
onPressed: () {
MinimalPersianCalendar.pickFullDate(
context: context,
onSubmit: (selectedDate, formattedDate) {
setState(() {
selectedText = formattedDate.jalali; // or formattedDate.gregorian
});
debugPrint('Jalali: ${formattedDate.jalali}');
debugPrint('Gregorian: ${formattedDate.gregorian}');
},
calendarType: CalendarType.jalali, // or CalendarType.gregorian
i18n: I18n(), // Customize i18n
showTodayBanner: true,
useGoToTodayButton: true,
);
},
child: const Text('Pick Full Date'),
)
For other methods (e.g., pickDay), use the same structure but adjust the pickDateFormat internally.
CustomDecorationPersianCalendar.pickFullDate #
ElevatedButton(
onPressed: () {
CustomDecorationPersianCalendar.pickFullDate(
context: context,
onSubmit: (selectedDate, formattedDate) {
setState(() {
selectedText = formattedDate.jalali;
});
debugPrint('Jalali: ${formattedDate.jalali}');
debugPrint('Gregorian: ${formattedDate.gregorian}');
},
calendarType: CalendarType.jalali,
background: Colors.cyan.shade50,
// Title box
titleBoxStyle: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)),
border: Border.all(color: Colors.cyan.shade500, width: 1.5),
color: Colors.cyan.shade600,
boxShadow: [
BoxShadow(
color: Colors.cyan.shade500,
offset: Offset.zero,
blurRadius: 25,
),
],
),
titleButtonStyle: TextButton.styleFrom(),
titleSelectedButtonStyle: TextButton.styleFrom(
elevation: 0,
backgroundColor: Colors.cyan.shade700,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
),
titleTextStyle: const TextStyle(color: Colors.white),
titleSelectedTextStyle: const TextStyle(color: Colors.white54),
// Date buttons
dateButtonStyle: TextButton.styleFrom(),
dateSelectedButtonStyle: TextButton.styleFrom(
elevation: 0,
backgroundColor: Colors.cyan.shade700,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
),
dateTextStyle: TextStyle(color: Colors.cyan.shade700),
dateSelectedTextStyle: const TextStyle(color: Colors.white54),
// Submit button
submitTitle: 'ثبت',
submitButtonStyle: ElevatedButton.styleFrom(
elevation: 10,
shadowColor: Colors.cyan.shade400,
backgroundColor: Colors.cyan.shade700,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0)),
),
submitTextStyle: TextStyle(color: Colors.cyan.shade100),
// Cancel button
cancelTitle: 'لغو',
cancelButtonStyle: TextButton.styleFrom(),
cancelTextStyle: TextStyle(color: Colors.cyan.shade700),
// Week days
weekDaysBoxStyle: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)),
border: Border.all(color: Colors.cyan.shade500, width: 1.5),
color: Colors.cyan.shade600,
),
weekDaysTextStyle: const TextStyle(color: Colors.white),
showTodayBanner: true,
useGoToTodayButton: true,
);
},
child: const Text('Pick Full Date (Custom)'),
)
Calendar Type Support #
calendarType: CalendarType.jalali // Persian
// or
calendarType: CalendarType.gregorian // Gregorian
First Day of Week #
firstDayOfWeek: FirstDayOfWeek.saturday, // Saturday first
// or FirstDayOfWeek.sunday, FirstDayOfWeek.monday
Persian Digits Support #
enablePersianDigits: true, // Persian digits (default)
// or false for Western Arabic digits
Internationalization (i18n) #
Customize texts via I18n:
i18n: I18n(
buttons: I18nButtons(
cancel: 'Cancel', // Or use app localization like S.current.cancel
submit: 'Submit',
goToday: 'Go to Today',
),
weekCodes: I18nWeekCodes(
saturday: 'ش', sunday: 'ی', monday: 'د', tuesday: 'س', wednesday: 'چ',
thursday: 'پ', friday: 'ج',
),
persianMonths: I18nPersianMonths(
farvardin: 'فروردین', ordibehesht: 'اردیبهشت', // etc.
),
gregorianMonths: I18nGregorianMonths(
january: 'January', february: 'February', // etc.
),
),
For full app localization, integrate with flutter_localizations and use S.of(context).key in I18n fields.
toPersianDigit Extension #
Convert numbers to Persian digits:
Text('123'.toPersianDigit()) // Outputs: ۱۲۳
Documentation #
GridViewCalendar Parameters #
| Parameter | Description | Type | Default |
|---|---|---|---|
builder |
Required callback to build each day tile | DayTileBuilder |
Required |
weekDayTileBuilder |
Optional callback for weekday headers | WeekDayTileBuilder? |
null (default headers) |
calendarType |
Jalali or Gregorian display | CalendarType? |
Persian |
initDate |
Initial year and month to display | InitDate? |
Current month/year |
firstDayOfWeek |
Starting day (Saturday for Persian, Monday for Gregorian) | FirstDayOfWeek? |
Auto-configured |
i18n |
Weekday and month names | I18n? |
Default I18n() |
mainAxisExtent |
Height of day tiles | double? |
Auto |
crossAxisSpacing |
Horizontal spacing between tiles | double? |
0.0 |
mainAxisSpacing |
Vertical spacing between rows | double? |
0.0 |
padding |
Overall padding | EdgeInsets? |
EdgeInsets.all(8) |
With these builders, developers can implement advanced features like event overlays, accessibility labels, animations, or integration with state management for dynamic calendars.
MinimalPersianCalendar Parameters #
| Parameter | Description | Type | Default |
|---|---|---|---|
context |
The BuildContext for showing the dialog | BuildContext |
Required |
onSubmit |
Callback with selected and formatted dates | OnPickDate? |
Required |
calendarType |
Calendar type (Jalali or Gregorian) | CalendarType |
Required |
initialDate |
Starting date | DateTime? |
DateTime.now() |
maxYear / minYear |
Year range (for full/year-month modes) | int? |
N/A |
borderRadius |
Dialog border radius | double? |
20.0 |
primaryColor |
Primary theme color | Color? |
Theme primary |
onPrimaryColor |
Text color on primary | Color? |
Theme onPrimary |
background |
Dialog background color | Color? |
Theme background |
titleTextStyle |
Unselected title text style | TextStyle? |
Default |
titleSelectedTextStyle |
Selected title text style | TextStyle? |
Default |
dateTextStyle |
Unselected date text style | TextStyle? |
Default |
dateSelectedTextStyle |
Selected date text style | TextStyle? |
Default |
submitTextStyle |
Submit button text style | TextStyle? |
Default |
cancelTextStyle |
Cancel button text style | TextStyle? |
Default |
showTodayBanner |
Show today date banner | bool? |
false |
useGoToTodayButton |
Show "Go to Today" button | bool? |
false |
weekDaysPadding |
Weekdays padding | EdgeInsetsGeometry? |
Default |
weekDaysTextStyle |
Weekdays text style | TextStyle? |
Default |
firstDayOfWeek |
Starting day of week | FirstDayOfWeek? |
Saturday |
i18n |
i18n configuration | I18n? |
Default I18n() |
enablePersianDigits |
Use Persian digits | bool? |
true |
Note: Minimal uses TextStyle for styling; deprecated string titles should use I18n instead.
CustomDecorationPersianCalendar Parameters #
Similar to Minimal, but with advanced styling:
| Parameter | Description | Type | Default |
|---|---|---|---|
context |
The BuildContext for showing the dialog | BuildContext |
Required |
onSubmit |
Callback with selected and formatted dates | OnPickDate? |
Required |
calendarType |
Calendar type (Jalali or Gregorian) | CalendarType |
Required |
initialDate |
Starting date | DateTime? |
DateTime.now() |
maxYear / minYear |
Year range (for full/year-month modes) | int? |
N/A |
borderRadius |
Dialog border radius | double? |
20.0 |
primaryColor |
Primary theme color | Color? |
Theme primary |
onPrimaryColor |
Text color on primary | Color? |
Theme onPrimary |
background |
Dialog background color | Color? |
Theme background |
titleBoxStyle |
Title container decoration | BoxDecoration? |
Default |
titleButtonStyle |
Unselected title button style | ButtonStyle? |
Default |
titleSelectedButtonStyle |
Selected title button style | ButtonStyle? |
Default |
titleTextStyle |
Unselected title text style | TextStyle? |
Default |
titleSelectedTextStyle |
Selected title text style | TextStyle? |
Default |
dateButtonStyle |
Unselected date button style | ButtonStyle? |
Default |
dateSelectedButtonStyle |
Selected date button style | ButtonStyle? |
Default |
dateTextStyle |
Unselected date text style | TextStyle? |
Default |
dateSelectedTextStyle |
Selected date text style | TextStyle? |
Default |
submitButtonStyle |
Submit button style | ButtonStyle? |
Default |
submitTextStyle |
Submit text style | TextStyle? |
Default |
cancelButtonStyle |
Cancel button style | ButtonStyle? |
Default |
cancelTextStyle |
Cancel text style | TextStyle? |
Default |
goButtonStyle |
"Go to Today" button style | ButtonStyle? |
Default |
weekDaysBoxStyle |
Weekdays container decoration | BoxDecoration? |
Default |
weekDaysPadding |
Weekdays padding | EdgeInsetsGeometry? |
Default |
weekDaysTextStyle |
Weekdays text style | TextStyle? |
Default |
firstDayOfWeek |
Starting day of week | FirstDayOfWeek? |
Saturday |
i18n |
i18n configuration | I18n? |
Default I18n() |
enablePersianDigits |
Use Persian digits | bool? |
true |
Deprecated string titles (submitTitle, etc.) should use I18n instead.
Contributing #
Contributions are welcome! Please open an issue on the GitHub repository for suggestions, bugs, or features.
To contribute code, read the CONTRIBUTING.md for guidelines.