Everything you need to know about the Bikram Sambat date picker for React.
date-picker-bs is a React component library that provides a date picker and calendar for the Bikram Sambat (Nepali) calendar system. It covers dates from BS 2000 to BS 2100 (AD 1943–2043) with high accuracy.
The library exports two main components:
DatePickerBS — A popover-based date picker with a trigger button.CalendarBS — A standalone inline calendar component.Both components share the same underlying calendar engine and support English and Nepali languages, date constraints, custom formatting, and extensive styling via className.
1npm install date-picker-bs1pnpm add date-picker-bs1yarn add date-picker-bsYou can also install via the shadcn/ui registry:
1npx shadcn@latest add https://date-picker-bs.vercel.app/r/date-picker-bs.jsonThe library requires the following peer dependencies:
react ^18.0.0 || ^19.0.0@radix-ui/react-popover ^1.0.0lucide-react ^0.400.0The simplest way to use the date picker:
1234567891011121314import { useState } from "react"import { DatePickerBS, getTodayBs } from "date-picker-bs" function App() { const [date, setDate] = useState(getTodayBs()) return ( <DatePickerBS value={date} onChange={setDate} className="w-[280px]" /> )}Use the standalone calendar component:
12345678910111213import { useState } from "react"import { CalendarBS } from "date-picker-bs" function App() { const [date, setDate] = useState() return ( <CalendarBS selected={date} onSelect={setDate} /> )}Set lang="ne" to display the calendar in Nepali:
123456<DatePickerBS lang="ne" value={date} onChange={setDate} className="w-[280px]"/>Override the display format with the formatOptions prop:
1234567<DatePickerBS value={date} onChange={setDate} formatOptions={{ pattern: "DD MMMM YYYY" }} placeholder="DD Month YYYY" className="w-[280px]"/>Control which month the calendar opens to with defaultMonth:
1234<CalendarBS defaultMonth={{ year: 2080, month: 10 }} onMonthChange={(m) => console.log("Month changed:", m)}/>Control the popover open state externally with open and onOpenChange:
12345678const [open, setOpen] = useState(false) <DatePickerBS value={date} onChange={setDate} open={open} onOpenChange={setOpen}/>Pass disabled to prevent interaction:
123456<DatePickerBS value={getTodayBs()} onChange={() => {}} disabled className="w-[280px]"/>Use DatePickerBS inside a form with a submit handler:
Combine two DatePickerBS instances for a start and end date range:
The DatePickerBS component wraps CalendarBS inside a Radix UI Popover. It accepts all CalendarBS props plus the following:
| Prop | Type | Default | Description |
|---|---|---|---|
| value | DateBS | undefined | — | The selected Bikram Sambat date. |
| onChange | (date: DateBS) => void | — | Called when a date is selected. |
| lang | "en" | "ne" | "en" | Display language. |
| minDate | DateBS | undefined | — | Earliest selectable date. |
| maxDate | DateBS | undefined | — | Latest selectable date. |
| disabled | boolean | false | Disables the entire picker. |
| disabled | (date: DateBS) => boolean | — | Custom function to disable specific days. |
| formatOptions | { pattern: string } | — | Override the display format of the trigger. |
| placeholder | string | "Pick a date" | Placeholder text when no date is selected. |
| open | boolean | — | Controlled open state of the popover. |
| onOpenChange | (open: boolean) => void | — | Called when the popover open state changes. |
| className | string | — | Additional classes for the trigger button. |
| popoverContentClassName | string | — | Additional classes for the popover content panel. |
The CalendarBS component is the core calendar view.
| Prop | Type | Default | Description |
|---|---|---|---|
| selected | DateBS | undefined | — | The selected date. |
| onSelect | (date: DateBS) => void | — | Called when a date is selected. |
| lang | "en" | "ne" | "en" | Display language. |
| defaultMonth | { year, month } | selected | today | Initial month to display on mount. |
| onMonthChange | (month: { year, month }) => void | — | Called when the displayed month changes via navigation. |
| minDate | DateBS | undefined | — | Earliest selectable date. |
| maxDate | DateBS | undefined | — | Latest selectable date. |
| disabled | (date: DateBS) => boolean | — | Custom function to disable specific days. |
| fromYear | number | 2000 | Earliest year shown in the year grid view. |
| toYear | number | 2100 | Latest year shown in the year grid view. |
| today | DateBS | undefined | getTodayBs() | Override the date used for "today" highlighting. |
| classNames | Partial<CalendarBSClassNames> | — | Override internal component classes for deep customization (20+ slots). |
The formatOptions.pattern prop accepts the following tokens:
| Token | Meaning | Example (en) | Example (ne) |
|---|---|---|---|
| YYYY | 4-digit year | 2081 | २०८१ |
| YY | 2-digit year | 81 | ८१ |
| MMMM | Full month name | Bhadra | भदौ |
| MMM | Abbreviated month | Bhad | भदौ |
| MM | 2-digit month | 05 | ०५ |
| DD | 2-digit day | 15 | १५ |
12345678910111213141516171819// ISO-like, numericformatOptions={{ pattern: "YYYY-MM-DD" }}// → "2081-05-15" // Full month nameformatOptions={{ pattern: "YYYY MMMM DD" }}// → "२०८१ भदौ १५" (Nepali) // Day firstformatOptions={{ pattern: "DD MMMM YYYY" }}// → "15 Bhadra 2081" (English) // Month day, yearformatOptions={{ pattern: "MMMM DD, YYYY" }}// → "Bhadra 15, 2081" // AbbreviatedformatOptions={{ pattern: "YYYY MMM DD" }}// → "2081 Bhad 15"The library ships with two languages: English (en) and Nepali (ne). When Nepali is selected:
12345// English (default)<DatePickerBS lang="en" value={date} onChange={setDate} /> // Nepali<DatePickerBS lang="ne" value={date} onChange={setDate} />Use the toNepaliNumber and parseNepaliNumber utilities for converting between Arabic and Nepali digits:
1234import { toNepaliNumber, parseNepaliNumber } from "date-picker-bs" toNepaliNumber(2081) // → "२०८१"parseNepaliNumber("२०८१") // → 2081Restrict the selectable range with minDate and maxDate:
1234567891011121314const today = getTodayBs()const nextWeek = { year: today.year, month: today.month, day: today.day + 7,} <DatePickerBS value={date} onChange={setDate} minDate={today} maxDate={nextWeek} className="w-[280px]"/>Use disabledDays for fine-grained control over which dates are selectable. Return true to disable a day:
12345678910111213// Disable weekends<DatePickerBS value={date} onChange={setDate} disabledDays={(d) => { const dayIndex = ( d.year * 365 + d.month * 30 + d.day ) % 7 return dayIndex === 0 || dayIndex === 6 }} placeholder="Weekdays only" className="w-[280px]"/>Today's date is automatically highlighted in the calendar with a distinct visual style. The getTodayBs() function returns the current date in the BS calendar system.
Click the month/year header in the calendar to toggle between month view and year grid view. The year grid shows 12 years per page with previous/next pagination — useful for quickly jumping across decades.
Control the visible year range with fromYear and toYear. These clamp both the month navigation and the year grid.
1234567// Restrict to BS 2075–2085<CalendarBS selected={date} onSelect={setDate} fromYear={2075} toYear={2085}/>Both components accept a className prop for custom styling. For DatePickerBS, this applies to the trigger button:
1<DatePickerBS value={date} onChange={setDate} className="w-[280px] h-10 text-sm" />The CalendarBS component accepts a classNames prop for deep customization of internal elements:
12345678910<CalendarBS selected={date} onSelect={setDate} classNames={{ month: "text-lg font-bold", day: "rounded-full hover:bg-primary/10", today: "ring-2 ring-primary", selected: "bg-primary text-primary-foreground", }}/>The component uses shadcn/ui-style CSS variables for theming. Override these variables in your global stylesheet to customize the look:
12345678910111213/* Your global CSS */:root { --background: 0 0% 100%; --foreground: 0 0% 4%; --card: 0 0% 100%; --popover: 0 0% 100%; --primary: 0 0% 9%; --primary-foreground: 0 0% 100%; --secondary: 0 0% 96%; --muted-foreground: 0 0% 46%; --border: 0 0% 90%; --radius: 0.5rem;}The core date type used throughout the library:
12345type DateBS = { year: number // BS year (e.g. 2081) month: number // 1-indexed month (1 = Baisakh) day: number // Day of month (1-32)}20+ named slots for deep styling of every calendar element (all optional):
123456789101112131415161718192021222324interface CalendarBSClassNames { caption: string captionLabel: string nav: string navButton: string navButtonPrev: string navButtonNext: string table: string headRow: string headCell: string row: string cell: string day: string daySelected: string dayToday: string dayOutside: string dayDisabled: string yearGrid: string yearCell: string yearButton: string yearSelected: string yearToday: string yearDisabled: string}Pass as Partial<CalendarBSClassNames> — all fields are optional.
All types and utilities are exported from the package entry point:
1234567891011121314151617181920212223242526272829303132333435363738import { // Components DatePickerBS, CalendarBS, // Types type DateBS, type BsLang, type BsFormatOptions, type CalendarDay, type CalendarBSClassNames, type CalendarBSProps, type DatePickerBSProps, type DatePickerMode, // Constants MONTHS, WEEKDAYS, // Utilities getTodayBs, formatBsDate, bsToAd, adToBs, getBsDayOfWeek, getDaysInBsMonth, getDaysInBsYear, getPrevMonth, getNextMonth, generateCalendarGrid, isSameBsDate, isBeforeBsDate, isAfterBsDate, isValidBsYear, getBsYearRange, toNepaliNumber, parseNepaliNumber,} from "date-picker-bs"All utilities from @nepali-utils/core are re-exported from date-picker-bs. Below is the complete API reference.
| Function | Returns | Description |
|---|---|---|
| getTodayBs() | DateBS | Current date in BS. Always succeeds. |
| bsToAd(year, month, day) | Date | BS → Date (AD). Throws if date is invalid or outside BS 2000–2100. |
| adToBs(date) | DateBS | Date (AD) → BS. Throws if before BS 2000-01-01 (AD 1943-04-14). |
| getBsDayOfWeek(year, month, day) | number (0–6) | Day of week: 0 = Sunday, 6 = Saturday. Throws on invalid date. |
| Function | Returns | Description |
|---|---|---|
| formatBsDate(date, lang?, opts?) | string | Format with pattern: YYYY-MM-DD, DD MMMM YYYY, etc. Default: YYYY-MM-DD. |
| toNepaliNumber(num) | string | Arabic → Nepali digits (e.g. 2081 → २०८१). Handles negatives. |
| parseNepaliNumber(str) | number | Nepali → Arabic (e.g. २०८१ → 2081). Non-digits pass through. |
| getPrevMonth(year, month) | { year, month } | Previous month (wraps year at Baisakh). |
| getNextMonth(year, month) | { year, month } | Next month (wraps year at Chaitra). |
| Function | Returns | Description |
|---|---|---|
| generateCalendarGrid(year, month, ...) | CalendarDay[][] | 6×7 grid (weeks × days) with today/selected/disabled/padding state. |
| getDaysInBsMonth(year, month) | number (29–32) | Days in a BS month. Throws if month is outside 1–12. |
| getDaysInBsYear(year) | number (354–366) | Total days in a BS year. Throws if outside BS 2000–2100. |
| isValidBsYear(year) | boolean | True if year is in BS 2000–2100. |
| getBsYearRange() | { min, max } | Returns { min: 2000, max: 2100 }. |
| Function | Returns | Description |
|---|---|---|
| isSameBsDate(a, b) | boolean | True if year, month, and day are all equal. |
| isBeforeBsDate(a, b) | boolean | True if a is before b (year → month → day). |
| isAfterBsDate(a, b) | boolean | True if a is after b. |
| Field | Type | Description |
|---|---|---|
| day | number | null | Day of month (null for padding cells) |
| date | DateBS | null | The BS date (null for padding) |
| isToday | boolean | Matches today's date |
| isSelected | boolean | Matches the selected date |
| isDisabled | boolean | Disabled by callback |
| isOutside | boolean | Padding cell outside current month |
1234567891011121314151617181920212223242526272829303132333435363738394041import { getTodayBs, formatBsDate, bsToAd, adToBs, toNepaliNumber, isSameBsDate, isBeforeBsDate, generateCalendarGrid,} from "date-picker-bs" // Get todayconst today = getTodayBs()// → { year: 2081, month: 5, day: 15 } // FormatformatBsDate(today, "en", { pattern: "YYYY MMMM DD" })// → "2081 Bhadra 15" formatBsDate(today, "ne", { pattern: "YYYY MMMM DD" })// → "२०८१ भदौ १५" // Convert BS → ADconst adDate = bsToAd(today.year, today.month, today.day)// → Date object // Convert AD → BSconst bsDate = adToBs(new Date())// → DateBS object // Compare datesisSameBsDate(today, { year: 2081, month: 5, day: 15 }) // → trueisBeforeBsDate({ year: 2080, month: 12, day: 30 }, today) // → true // Nepali numeralstoNepaliNumber(2081) // → "२०८१"parseNepaliNumber("२०८१") // → 2081 // Calendar gridconst weeks = generateCalendarGrid(2081, 5)// → CalendarDay[][] — ready for renderingStill have questions?
Check the source on GitHub or open an issue.