bs_ad_calendar
A fully customizable Nepali (Bikram Sambat) and English (Gregorian) calendar widget for Flutter.
Demo
Check out the demo video and screenshots to see the calendar in action!
Try it on Your Device
Want to test the calendar on your device? Clone and run the full test application:
git clone https://github.com/bibashpoudel7/calendar_test_app.git
cd calendar_test_app
flutter pub get
flutter run
- Dual calendar modes: Nepali (Bikram Sambat) OR English (Gregorian) calendar display
- AD ↔ BS date conversion (BS 1970 – 2250)
- Interactive monthly calendar widget with tap-to-jump year/month picker
- Single-date picker dialog (
showNepaliDatePicker) - Date range picker dialog (
showNepaliDateRangePicker) - Range selection mode with highlighted start/end caps and in-range bar
- Tri-locale: English (
Baisakh), Nepali (बैशाख), or Both simultaneously - Optional dual date display – show both calendars simultaneously
DatePriority– choose whether BS or AD is the large primary number- Secondary date color customization – customize sub-date colors for selected/today states
- One-stop theme object (
NepaliCalendarThemeData) - Event markers with custom builder
- Zero extra dependencies – Flutter SDK only
Installation
dependencies:
bs_ad_calendar: ^1.0.0
Quick start
import 'package:bs_ad_calendar/bs_ad_calendar.dart';
Calendar Modes
This package supports two distinct calendar modes:
- Nepali (Bikram Sambat) Calendar – Uses Nepali month structure (Baisakh, Jestha, Ashadh, etc.)
- Gregorian (English) Calendar – Uses standard English month structure (January, February, March, etc.)
You can choose the calendar mode and display format based on your needs:
| Calendar Mode | Primary Display | Optional Secondary Display |
|---|---|---|
| Nepali | BS dates (Baisakh-Chaitra) | AD dates (optional sub-label) |
| Gregorian | AD dates (January-December) | BS dates (optional sub-label) |
Usage
1. Gregorian (English) calendar with optional Nepali dates
Display a standard English calendar with Gregorian month structure:
GregorianCalendarWidget(
initialDate: DateTime.now(),
theme: NepaliCalendarThemeData(
primaryColor: Colors.deepPurple,
dayFontSize: 14,
showNepaliDate: true, // Show BS dates as sub-labels
secondaryDateColor: Colors.grey,
selectedSecondaryDateColor: Colors.white,
todaySecondaryDateColor: Colors.white,
),
onDaySelected: (DateTime adDate, NepaliDate bsDate) {
print('AD: $adDate, BS: $bsDate');
},
)
Key features:
- Standard Gregorian month structure (January has 31 days, February has 28/29, etc.)
- Optional Nepali date sub-labels with customizable colors
- Perfect for apps that primarily use English calendar but need BS reference
2. Nepali calendar with optional English dates
Display a Nepali (Bikram Sambat) calendar:
NepaliCalendarWidget(
initialDate: NepaliDateConverter.today(),
locale: NepaliLocale.english,
theme: NepaliCalendarThemeData(
primaryColor: Colors.indigo,
showEnglishDate: true, // Show AD dates as sub-labels
datePriority: DatePriority.nepali, // BS large, AD small
dayFontSize: 14,
secondaryDateColor: Colors.grey,
selectedSecondaryDateColor: Colors.white,
),
onDaySelected: (NepaliDate bsDate, DateTime adDate) {
print('BS: $bsDate, AD: $adDate');
},
)
3. Single date picker dialog
final result = await showNepaliDatePicker(
context: context,
initialDate: NepaliDateConverter.today(),
locale: NepaliLocale.english,
theme: NepaliCalendarThemeData(
primaryColor: Colors.indigo,
showEnglishDate: true,
dayFontSize: 14,
),
);
if (result != null) {
print('BS : ${result.bsDate}'); // 2081-04-15
print('Readable : ${result.bsDate.toReadableStringEn()}'); // 15 Shrawan, 2081
print('AD : ${result.adDate}'); // 2024-07-30
}
4. Date range picker dialog
final result = await showNepaliDateRangePicker(
context: context,
locale: NepaliLocale.english,
theme: NepaliCalendarThemeData(primaryColor: Colors.teal),
rangeStyle: NepaliCalendarRangeStyle(
rangeStartDecoration: BoxDecoration(
color: Colors.teal,
shape: BoxShape.circle,
),
rangeEndDecoration: BoxDecoration(
color: Colors.teal,
shape: BoxShape.circle,
),
inRangeDecoration: BoxDecoration(
color: Color(0x2200897B), // 13% teal
),
inRangeTextStyle: TextStyle(color: Colors.teal),
),
);
if (result != null) {
print('BS start : ${result.bsRange.start}'); // 2081-04-10
print('BS end : ${result.bsRange.end}'); // 2081-04-20
print('AD start : ${result.adStart}');
print('AD end : ${result.adEnd}');
}
5. Inline calendar widget — range selection
NepaliCalendarWidget(
selectionMode: NepaliSelectionMode.range,
rangeStyle: NepaliCalendarRangeStyle(
rangeStartDecoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
rangeEndDecoration: BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
inRangeDecoration: BoxDecoration(
color: Color(0x33E53935),
),
),
onRangeSelected: (NepaliDateRange range) {
print('Start: ${range.start}');
print('End : ${range.end}');
print('Days : ${range.contains(NepaliDate(2081, 4, 15))}');
},
)
Range selection works in two taps:
- First tap — sets the start date, highlights it with a circle cap.
- Second tap — sets the end date (auto-swaps if end < start), highlights the bar between them and fires
onRangeSelected. - Third tap — resets and starts a new range.
6. Event markers
NepaliCalendarWidget(
eventLoader: (NepaliDate day) => myEvents[day] ?? [],
markerBuilder: (context, day, events) {
return Container(
width: 6, height: 6,
decoration: const BoxDecoration(
color: Colors.orange,
shape: BoxShape.circle,
),
);
},
onDaySelected: (bs, ad) {},
)
7. Manual conversion
// AD → BS
final bs = NepaliDateConverter.adToBs(DateTime.now());
print(bs.toReadableStringEn()); // "30 Shrawan, 2081"
print(bs.toReadableStringNp()); // "३० साउन, २०८१"
// BS → AD
final ad = NepaliDateConverter.bsToAd(NepaliDate(2081, 4, 15));
print(ad); // 2024-07-30
// Days in a month
print(NepaliDateConverter.daysInMonth(2081, 1)); // 31
// Today in BS
final today = NepaliDateConverter.today();
Theming
One-stop theme object (recommended)
Pass a single NepaliCalendarThemeData to style everything at once:
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
primaryColor: Colors.deepPurple, // accent for today, selected, chevrons
dayFontSize: 14,
showEnglishDate: true, // show AD day number in each cell
datePriority: DatePriority.nepali, // BS day large, AD day small
headerBackgroundColor: Colors.deepPurple.shade50,
weekdayRowBackgroundColor: Colors.deepPurple.shade50,
todayCellShape: BoxShape.circle,
selectedCellShape: BoxShape.circle,
),
onDaySelected: (bs, ad) {},
)
NepaliCalendarThemeData field |
Default | Description |
|---|---|---|
primaryColor |
Color(0xFFE53935) |
Accent for today circle, chevrons, confirm button |
backgroundColor |
null |
Calendar card background |
headerBackgroundColor |
null |
Header row background |
weekdayRowBackgroundColor |
null |
Day-of-week row background |
dayColor |
Colors.black87 |
Regular day number colour |
disabledDayColor |
Colors.black26 |
Out-of-range day colour |
todayTextColor |
Colors.white |
Today's number colour |
selectedTextColor |
Colors.white |
Selected day number colour |
weekdayColor |
Colors.black54 |
Weekday label colour |
secondaryDateColor |
Colors.black54 |
Sub-date colour for normal days |
selectedSecondaryDateColor |
Colors.white |
Sub-date colour when selected |
todaySecondaryDateColor |
Colors.white |
Sub-date colour for today |
dayFontSize |
13 |
Day number font size |
englishDateFontSize |
9 |
AD sub-label font size |
titleFontSize |
16 |
Header title font size |
weekdayFontSize |
12 |
Weekday label font size |
showEnglishDate |
false |
Show AD day in small text (Nepali calendar) |
showNepaliDate |
true |
Show BS day in small text (Gregorian calendar) |
datePriority |
DatePriority.nepali |
Which date is the large primary number |
cellSize |
auto (38 / 46) |
Day cell size in logical pixels |
weekdayRowHeight |
28 |
Height of weekday header row |
todayCellShape |
BoxShape.circle |
Today circle shape |
selectedCellShape |
BoxShape.circle |
Selected day shape |
Granular style overrides
For fine-grained control, pass individual style objects. These override theme when provided.
NepaliCalendarWidget(
calendarStyle: NepaliCalendarStyle(
showEnglishDate: true,
datePriority: DatePriority.english, // AD day large, BS day small
cellSize: 42.0,
todayDecoration: BoxDecoration(color: Colors.blue, shape: BoxShape.circle),
selectedDecoration: BoxDecoration(color: Colors.blue.shade200, shape: BoxShape.circle),
defaultTextStyle: TextStyle(fontSize: 14),
englishDateTextStyle: TextStyle(fontSize: 9, color: Colors.grey),
),
headerStyle: NepaliHeaderStyle(
titleTextStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
leftChevronIcon: Icon(Icons.arrow_back_ios, color: Colors.blue),
rightChevronIcon: Icon(Icons.arrow_forward_ios, color: Colors.blue),
),
daysOfWeekStyle: NepaliDaysOfWeekStyle(
weekdayTextStyle: TextStyle(fontSize: 13, color: Colors.black54),
weekendTextStyle: TextStyle(fontSize: 13, color: Colors.red),
rowHeight: 32,
),
onDaySelected: (bs, ad) {},
)
| Style class | Controls |
|---|---|
NepaliCalendarStyle |
Day cell decorations, text styles, showEnglishDate, datePriority, cell size |
NepaliHeaderStyle |
Month/year title, chevron icons, background colour |
NepaliDaysOfWeekStyle |
Weekday label styles, row height, background |
NepaliCalendarRangeStyle |
Range start/end cap decorations, in-range bar colour and text styles |
Range style
NepaliCalendarRangeStyle(
rangeStartDecoration: BoxDecoration(
color: Color(0xFFE53935),
shape: BoxShape.circle,
),
rangeEndDecoration: BoxDecoration(
color: Color(0xFFE53935),
shape: BoxShape.circle,
),
inRangeDecoration: BoxDecoration(
color: Color(0x33E53935), // 20% opacity red
),
rangeStartTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
rangeEndTextStyle: TextStyle(color: Colors.white, fontWeight: FontWeight.bold),
inRangeTextStyle: TextStyle(color: Color(0xFFE53935)),
useRoundedRangeBar: true,
)
Locale options
| Value | Weekday header | Month title |
|---|---|---|
NepaliLocale.english |
Sun, Mon … Sat | Baisakh 2081 |
NepaliLocale.nepali |
आइत, सोम … शनि | बैशाख २०८१ |
NepaliLocale.both |
Two-line: Nepali top, English below | Baisakh 2081 / बैशाख २०८१ |
NepaliCalendarWidget(
locale: NepaliLocale.both,
onDaySelected: (bs, ad) {},
)
Date priority
Controls which calendar system's day number is rendered large (primary) when showEnglishDate is true:
DatePriority |
Large (primary) | Small (secondary) |
|---|---|---|
DatePriority.nepali (default) |
BS day | AD day |
DatePriority.english |
AD day | BS day (or hidden) |
Variant 1 — BS only (default)
BS day large, no AD sub-label.
NepaliCalendarWidget(
onDaySelected: (bs, ad) {},
)
Variant 2 — BS large, AD small
BS day large, AD day shown as a small sub-label below.
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
showEnglishDate: true,
datePriority: DatePriority.nepali, // default
),
onDaySelected: (bs, ad) {},
)
Variant 3 — AD large, BS small
AD day large, BS day shown as a small sub-label below.
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
showEnglishDate: true,
datePriority: DatePriority.english,
),
onDaySelected: (bs, ad) {},
)
Variant 4 — AD only (no BS sub-label)
AD day large, BS sub-label hidden entirely. Header and weekday row also show in English (Gregorian month name + English weekday abbreviations).
NepaliCalendarWidget(
theme: NepaliCalendarThemeData(
showEnglishDate: true,
datePriority: DatePriority.english,
showNepaliDate: false, // hide BS sub-label
),
onDaySelected: (bs, ad) {},
)
Year / month picker
Tapping the header title opens an interactive picker with a scrollable 4-column year grid (respecting firstDate and lastDate) and a 12-button month grid. The year list auto-scrolls to the currently displayed year.
Supported date range
| Calendar | From | To |
|---|---|---|
| BS | 1970/01/01 | 2250/12/30 |
| AD | 1913/04/13 | ~2193 |
Years 1970–2100 use a verified lookup table. Years 2101–2250 use the 91-year BS cycle algorithm for month-length calculation.
API reference
GregorianCalendarWidget
A calendar widget that displays standard Gregorian (English) months with optional Nepali date sub-labels.
| Parameter | Type | Default | Description |
|---|---|---|---|
initialDate |
DateTime |
required | Month displayed on first render |
selectedDate |
DateTime? |
null |
Pre-selected date |
firstDate |
DateTime |
DateTime(1900) |
Earliest selectable date |
lastDate |
DateTime |
DateTime(2100) |
Latest selectable date |
theme |
NepaliCalendarThemeData |
required | Calendar theme |
showNepaliDate |
bool |
false |
Show BS dates as sub-labels |
onDaySelected |
void Function(DateTime, NepaliDate)? |
null |
Day tap callback |
Example:
GregorianCalendarWidget(
initialDate: DateTime.now(),
theme: NepaliCalendarThemeData(
primaryColor: Colors.blue,
showNepaliDate: true,
secondaryDateColor: Colors.grey,
selectedSecondaryDateColor: Colors.white,
),
onDaySelected: (adDate, bsDate) {
print('Selected: $adDate (BS: $bsDate)');
},
)
NepaliCalendarWidget
A calendar widget that displays Nepali (Bikram Sambat) months with optional English date sub-labels.
| Parameter | Type | Default | Description |
|---|---|---|---|
initialDate |
NepaliDate? |
today | Month displayed on first render |
selectedDate |
NepaliDate? |
null |
Controlled selected date (single mode) |
firstDate |
NepaliDate |
NepaliDate(1970,1,1) |
Earliest selectable date |
lastDate |
NepaliDate |
NepaliDate(2250,12,30) |
Latest selectable date |
locale |
NepaliLocale |
.english |
Label language |
theme |
NepaliCalendarThemeData? |
null |
One-stop theme |
calendarStyle |
NepaliCalendarStyle? |
null |
Day cell overrides |
headerStyle |
NepaliHeaderStyle? |
null |
Header overrides |
daysOfWeekStyle |
NepaliDaysOfWeekStyle? |
null |
Weekday row overrides |
selectionMode |
NepaliSelectionMode |
.single |
Single or range selection |
rangeStartDate |
NepaliDate? |
null |
Pre-selected range start |
rangeEndDate |
NepaliDate? |
null |
Pre-selected range end |
rangeStyle |
NepaliCalendarRangeStyle |
red defaults | Range highlight style |
eventLoader |
List<Object> Function(NepaliDate)? |
null |
Provide events per day |
markerBuilder |
Widget Function(...)? |
null |
Custom event marker widget |
onDaySelected |
void Function(NepaliDate, DateTime)? |
null |
Single-mode tap callback |
onRangeSelected |
void Function(NepaliDateRange)? |
null |
Range-mode complete callback |
onPageChanged |
void Function(int year, int month)? |
null |
Month navigation callback |
showNepaliDatePicker
Returns NepaliDatePickerResult? with .bsDate and .adDate.
showNepaliDateRangePicker
Returns NepaliDateRangePickerResult? with .bsRange (NepaliDateRange), .adStart, and .adEnd.
NepaliDate
NepaliDate(2081, 4, 15)
date.year // 2081
date.month // 4
date.day // 15
date.monthNameEn // "Shrawan"
date.monthNameNp // "साउन"
date.toFormattedString() // "2081-04-15"
date.toReadableStringEn() // "15 Shrawan, 2081"
date.toReadableStringNp() // "१५ साउन, २०८१"
date.isSameDay(other)
date.isBefore(other)
date.isAfter(other)
date.isAtOrAfter(other)
date.isAtOrBefore(other)
date.copyWith(year: 2082)
NepaliDate.toNepaliNumerals(2081) // "२०८१"
NepaliDateRange
NepaliDateRange(
start: NepaliDate(2081, 4, 10),
end: NepaliDate(2081, 4, 20),
)
range.isSingleDay // false
range.contains(someDate) // true/false
range.toString() // "2081-04-10 – 2081-04-20"
Author
Bibash Poudel Sr. Full Stack Developer pdlbibash77@gmail.com
License
MIT © Bibash Poudel
Libraries
- bs_ad_calendar
- A fully customizable Nepali (Bikram Sambat) and Gregorian calendar package for Flutter.