Docs/date-picker-bs

date-picker-bs

Everything you need to know about the Bikram Sambat date picker for React.

Getting started

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.

Installation

Package manager

terminal
bash
1
npm install date-picker-bs
terminal
bash
1
pnpm add date-picker-bs
terminal
bash
1
yarn add date-picker-bs

shadcn/ui registry

You can also install via the shadcn/ui registry:

terminal
bash
1
npx shadcn@latest add https://date-picker-bs.vercel.app/r/date-picker-bs.json

Peer dependencies

The library requires the following peer dependencies:

  • react ^18.0.0 || ^19.0.0
  • @radix-ui/react-popover ^1.0.0
  • lucide-react ^0.400.0

Usage

Basic DatePickerBS

The simplest way to use the date picker:

app.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { 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]"
/>
)
}

Basic CalendarBS

Use the standalone calendar component:

1
2
3
4
5
6
7
8
9
10
11
12
13
import { useState } from "react"
import { CalendarBS } from "date-picker-bs"
function App() {
const [date, setDate] = useState()
return (
<CalendarBS
selected={date}
onSelect={setDate}
/>
)
}

Nepali language

Set lang="ne" to display the calendar in Nepali:

1
2
3
4
5
6
<DatePickerBS
lang="ne"
value={date}
onChange={setDate}
className="w-[280px]"
/>

Custom format

Override the display format with the formatOptions prop:

1
2
3
4
5
6
7
<DatePickerBS
value={date}
onChange={setDate}
formatOptions={{ pattern: "DD MMMM YYYY" }}
placeholder="DD Month YYYY"
className="w-[280px]"
/>

Default month

Control which month the calendar opens to with defaultMonth:

1
2
3
4
<CalendarBS
defaultMonth={{ year: 2080, month: 10 }}
onMonthChange={(m) => console.log("Month changed:", m)}
/>

Controlled open state

Control the popover open state externally with open and onOpenChange:

1
2
3
4
5
6
7
8
const [open, setOpen] = useState(false)
<DatePickerBS
value={date}
onChange={setDate}
open={open}
onOpenChange={setOpen}
/>

Disabled state

Pass disabled to prevent interaction:

1
2
3
4
5
6
<DatePickerBS
value={getTodayBs()}
onChange={() => {}}
disabled
className="w-[280px]"
/>

Examples

Form integration

Use DatePickerBS inside a form with a submit handler:

Date range picker

Combine two DatePickerBS instances for a start and end date range:

DatePickerBS props

The DatePickerBS component wraps CalendarBS inside a Radix UI Popover. It accepts all CalendarBS props plus the following:

PropTypeDefaultDescription
valueDateBS | undefinedThe selected Bikram Sambat date.
onChange(date: DateBS) => voidCalled when a date is selected.
lang"en" | "ne""en"Display language.
minDateDateBS | undefinedEarliest selectable date.
maxDateDateBS | undefinedLatest selectable date.
disabledbooleanfalseDisables the entire picker.
disabled(date: DateBS) => booleanCustom function to disable specific days.
formatOptions{ pattern: string }Override the display format of the trigger.
placeholderstring"Pick a date"Placeholder text when no date is selected.
openbooleanControlled open state of the popover.
onOpenChange(open: boolean) => voidCalled when the popover open state changes.
classNamestringAdditional classes for the trigger button.
popoverContentClassNamestringAdditional classes for the popover content panel.

CalendarBS props

The CalendarBS component is the core calendar view.

PropTypeDefaultDescription
selectedDateBS | undefinedThe selected date.
onSelect(date: DateBS) => voidCalled when a date is selected.
lang"en" | "ne""en"Display language.
defaultMonth{ year, month }selected | todayInitial month to display on mount.
onMonthChange(month: { year, month }) => voidCalled when the displayed month changes via navigation.
minDateDateBS | undefinedEarliest selectable date.
maxDateDateBS | undefinedLatest selectable date.
disabled(date: DateBS) => booleanCustom function to disable specific days.
fromYearnumber2000Earliest year shown in the year grid view.
toYearnumber2100Latest year shown in the year grid view.
todayDateBS | undefinedgetTodayBs()Override the date used for "today" highlighting.
classNamesPartial<CalendarBSClassNames>Override internal component classes for deep customization (20+ slots).

Format patterns

The formatOptions.pattern prop accepts the following tokens:

TokenMeaningExample (en)Example (ne)
YYYY4-digit year2081२०८१
YY2-digit year81८१
MMMMFull month nameBhadraभदौ
MMMAbbreviated monthBhadभदौ
MM2-digit month05०५
DD2-digit day15१५

Example patterns

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ISO-like, numeric
formatOptions={{ pattern: "YYYY-MM-DD" }}
// → "2081-05-15"
// Full month name
formatOptions={{ pattern: "YYYY MMMM DD" }}
// → "२०८१ भदौ १५" (Nepali)
// Day first
formatOptions={{ pattern: "DD MMMM YYYY" }}
// → "15 Bhadra 2081" (English)
// Month day, year
formatOptions={{ pattern: "MMMM DD, YYYY" }}
// → "Bhadra 15, 2081"
// Abbreviated
formatOptions={{ pattern: "YYYY MMM DD" }}
// → "2081 Bhad 15"

Language & localization

The library ships with two languages: English (en) and Nepali (ne). When Nepali is selected:

  • Month names appear in Devanagari script (बैशाख, जेष्ठ, असार, ...)
  • Weekday headers show Nepali abbreviations (आइत, सोम, ...)
  • Numerals use Nepali digits (०, १, २, ३, ...)
  • Navigation button labels remain in English for consistency
1
2
3
4
5
// English (default)
<DatePickerBS lang="en" value={date} onChange={setDate} />
// Nepali
<DatePickerBS lang="ne" value={date} onChange={setDate} />

Nepali numerals

Use the toNepaliNumber and parseNepaliNumber utilities for converting between Arabic and Nepali digits:

1
2
3
4
import { toNepaliNumber, parseNepaliNumber } from "date-picker-bs"
toNepaliNumber(2081) // → "२०८१"
parseNepaliNumber("२०८१") // → 2081

Date constraints

Min / max date

Restrict the selectable range with minDate and maxDate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const 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]"
/>

Disabled days callback

Use disabledDays for fine-grained control over which dates are selectable. Return true to disable a day:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 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 highlighting

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.

Year grid

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.

1
2
3
4
5
6
7
// Restrict to BS 2075–2085
<CalendarBS
selected={date}
onSelect={setDate}
fromYear={2075}
toYear={2085}
/>

Styling

Via className

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" />

Via CalendarClassNames

The CalendarBS component accepts a classNames prop for deep customization of internal elements:

1
2
3
4
5
6
7
8
9
10
<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",
}}
/>

CSS variables

The component uses shadcn/ui-style CSS variables for theming. Override these variables in your global stylesheet to customize the look:

css
1
2
3
4
5
6
7
8
9
10
11
12
13
/* 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;
}

TypeScript

DateBS type

The core date type used throughout the library:

1
2
3
4
5
type DateBS = {
year: number // BS year (e.g. 2081)
month: number // 1-indexed month (1 = Baisakh)
day: number // Day of month (1-32)
}

CalendarBSClassNames type

20+ named slots for deep styling of every calendar element (all optional):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
interface 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.

Imports

All types and utilities are exported from the package entry point:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import {
// 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"

Utility functions

All utilities from @nepali-utils/core are re-exported from date-picker-bs. Below is the complete API reference.

Conversion

FunctionReturnsDescription
getTodayBs()DateBSCurrent date in BS. Always succeeds.
bsToAd(year, month, day)DateBS → Date (AD). Throws if date is invalid or outside BS 2000–2100.
adToBs(date)DateBSDate (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.

Formatting & navigation

FunctionReturnsDescription
formatBsDate(date, lang?, opts?)stringFormat with pattern: YYYY-MM-DD, DD MMMM YYYY, etc. Default: YYYY-MM-DD.
toNepaliNumber(num)stringArabic → Nepali digits (e.g. 2081 → २०८१). Handles negatives.
parseNepaliNumber(str)numberNepali → 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).

Calendar data

FunctionReturnsDescription
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)booleanTrue if year is in BS 2000–2100.
getBsYearRange(){ min, max }Returns { min: 2000, max: 2100 }.

Comparison

FunctionReturnsDescription
isSameBsDate(a, b)booleanTrue if year, month, and day are all equal.
isBeforeBsDate(a, b)booleanTrue if a is before b (year → month → day).
isAfterBsDate(a, b)booleanTrue if a is after b.

CalendarDay fields

FieldTypeDescription
daynumber | nullDay of month (null for padding cells)
dateDateBS | nullThe BS date (null for padding)
isTodaybooleanMatches today's date
isSelectedbooleanMatches the selected date
isDisabledbooleanDisabled by callback
isOutsidebooleanPadding cell outside current month

Usage examples

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import {
getTodayBs,
formatBsDate,
bsToAd,
adToBs,
toNepaliNumber,
isSameBsDate,
isBeforeBsDate,
generateCalendarGrid,
} from "date-picker-bs"
// Get today
const today = getTodayBs()
// → { year: 2081, month: 5, day: 15 }
// Format
formatBsDate(today, "en", { pattern: "YYYY MMMM DD" })
// → "2081 Bhadra 15"
formatBsDate(today, "ne", { pattern: "YYYY MMMM DD" })
// → "२०८१ भदौ १५"
// Convert BS → AD
const adDate = bsToAd(today.year, today.month, today.day)
// → Date object
// Convert AD → BS
const bsDate = adToBs(new Date())
// → DateBS object
// Compare dates
isSameBsDate(today, { year: 2081, month: 5, day: 15 }) // → true
isBeforeBsDate({ year: 2080, month: 12, day: 30 }, today) // → true
// Nepali numerals
toNepaliNumber(2081) // → "२०८१"
parseNepaliNumber("२०८१") // → 2081
// Calendar grid
const weeks = generateCalendarGrid(2081, 5)
// → CalendarDay[][] — ready for rendering

Still have questions?

Check the source on GitHub or open an issue.