react-bs-ad-datepicker
v1.0.3
Published
Nepali date picker for React with Bikram Sambat (BS) and Gregorian (AD) calendar — BS to AD converter, date range picker, popup, Nepali localization, dark mode, themeable, TypeScript.
Maintainers
Keywords
Readme
react-bs-ad-datepicker
The Nepali date picker for React with full BS to AD and AD to BS conversion — a dual-calendar component supporting Bikram Sambat (BS) (Nepal's official calendar) alongside the Gregorian (AD) system. Use it as a Bikram Sambat datepicker, BS calendar, Nepali date converter, or a general-purpose React date picker with range selection, popup, theming, and more. All conversions are offline — no API calls needed.
🚀 Live Demo → — Explore all features, themes, and modes.
Why react-bs-ad-datepicker?
The Bikram Sambat (B.S.) calendar is Nepal's official calendar and differs significantly from the Gregorian system. Most React date pickers only support AD, forcing Nepali developers to manually build BS to AD or AD to BS converters. This library is a complete React Nepali date picker and BS date converter that works offline with:
- Offline BS calendar data — no API calls; years 2000–2090 built in
- Automatic AD ⇄ BS conversion — BS to AD and AD to BS, every date returns both
- Nepali localization — English and Nepali (नेपाली), with Nepali month names
- Multiple modes — date picker, range selector, popup, editable input, dual-month
- Full accessibility — ARIA labels, keyboard navigation, focus management
Features
🇳🇵 Bikram Sambat (BS) + Gregorian (AD) Calendar
- BS to AD and AD to BS conversion built in — every
DualDatereturns both calendars - Offline BS calendar engine with data for BS years 2000–2090
- Nepali month names: Baishakh, Jestha, Ashadh, Shrawan, Bhadra, Ashwin, Kartik, Mangsir, Poush, Magh, Falgun, Chaitra
- Use it as a BS datepicker, AD datepicker, or dual calendar simultaneously
📅 Interaction Modes
- Single date picker — click to select a date
- Range selector — pick start and end dates
- Popup / dropdown — attach to any trigger element with portal rendering
- Editable input picker — type dates in ISO, display, or slash format
- Dual-month view — two months side by side for quicker range selection
🎨 Theming & Visual
- Light / Dark / Auto themes
- Custom color tokens — primary, primaryLight, primaryDark, background, text
- Radius & cell size variants —
sm,md,lg - Visual styles — filled, outlined, ghost
- Smooth animations — toggle with
animateprop - Highlight today — optional today cell highlighting
📋 Date Constraints & Validation
minDate/maxDateboundsdisabledDates— block specific datesdisabledDays— block days of the week (e.g. weekends)disabledRanges— block date spansisDateDisabled— custom validation functiononBeforeSelect— async gate for selection approval
🏷️ Events & Highlights
- Rich event objects with
id,title,type,color,badge,icon,tooltip highlightedDates— call attention to specific daysonLoadEvents— async event loading per month (fetch from API)- Custom day rendering via
renderDay
🔌 Extensible Engine
- Register custom calendar engines via
registerEngine() - Build fiscal year, Hijri, or any other calendar system
- All date arithmetic goes through
ctx.engine.*()— engine-agnostic presets
⌨️ Keyboard & Accessibility
shortcuts— ⌘T to go to today, Escape to close popup- Full focus management
- ARIA labels and screen reader support
📦 TypeScript
- Complete type declarations shipped with the package
- Strict TypeScript support with
verbatimModuleSyntaxanderasableSyntaxOnly
Installation
npm install react-bs-ad-datepickerRequires React 18+ or React 19+.
Quick Start
import { Calendar } from 'react-bs-ad-datepicker'
import 'react-bs-ad-datepicker/dist/calendar.css'
export default function App() {
return (
<Calendar
type="BS"
mode="single"
theme="light"
onChange={(d) => console.log(d.ad, d.bs)}
/>
)
}Examples
📌 Single Date Picker
The most basic usage — select a single BS or AD date:
<Calendar
type="AD"
mode="single"
onChange={(date) => console.log(date.ad, date.bs)}
/>📌 Range Selection
Select a date range with preset quick-select options:
<Calendar
type="BS"
mode="range"
showPresets
showDualDisplay
animate
onRangeChange={(r) => console.log(r.start, r.end)}
/>📌 Popup / Dropdown Date Picker
Attach the calendar to any element (button, input, icon) with portal rendering:
<Calendar
type="BS"
trigger={<button>📅 Pick dates</button>}
placement="bottom-start"
portal
/>📌 Editable Input Date Picker
Type dates manually or pick from the calendar — supports multiple formats:
<Calendar
ref={calRef}
type="BS"
mode="single"
portal
placement="auto"
showDualDisplay
animate
open={isOpen}
onOpenChange={setIsOpen}
value={selectedDate}
onChange={(d) => { setSelectedDate(d); setIsOpen(false) }}
trigger={
<div className="nc-input-wrap">
<input className="nc-input" value={value} onChange={handleInput} placeholder="YYYY-MM-DD" />
<span className="nc-input-icon" onClick={handleIconClick}>📅</span>
</div>
}
/>Supported input formats:
| Format | Example (AD) | Example (BS) |
|--------|-------------|-------------|
| YYYY-MM-DD (ISO) | 2026-07-04 | 2083-03-20 |
| Mon DD, YYYY | Jul 4, 2026 | Shrawan 20, 2083 |
| DD/MM/YYYY | 04/07/2026 | 20/04/2083 |
Note: Input click does not open the popup — use the icon button to toggle.
📌 Dual Month View
Two calendars side by side for faster date range browsing:
<Calendar
type="AD"
dualMonth
mode="range"
themeTokens={{ primaryColor: '#6366f1' }}
/>📌 Events & Highlights
Display events on the calendar with badges, colors, and tooltips:
import { Conv } from 'react-bs-ad-datepicker'
const events = [
{
id: '1',
date: Conv.dualAD({ year: 2026, month: 6, day: 16 }),
title: 'Team Sync',
type: 'meeting',
color: '#e11d48',
badge: 'New',
},
]
<Calendar type="AD" events={events} />📌 Custom Preset Ranges
Define reusable date ranges using engine-agnostic arithmetic:
import type { PresetRange } from 'react-bs-ad-datepicker'
const customPresets: PresetRange[] = [
{
label: 'Next Week',
icon: '→',
getValue: (ctx) => {
if (!ctx) return { start: null, end: null }
const t = ctx.engine.getToday()
return {
start: ctx.engine.addDays(t, 1),
end: ctx.engine.addDays(t, 7),
}
},
},
]
<Calendar type="BS" mode="range" showPresets presetRanges={customPresets} />📌 Custom Calendar Engines
Register a custom engine for fiscal, Hijri, or any other calendar system:
import { registerEngine } from 'react-bs-ad-datepicker'
import type { CalEngine } from 'react-bs-ad-datepicker'
const fiscalEngine: CalEngine = {
type: 'Fiscal',
getMonthNames: () => ['Month 1', 'Month 2', /* ... */],
getDayNames: () => ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
getDaysInMonth: (y, m) => m === 11 ? 31 : 30,
getStartDow: (y, m) => new Date(y, m, 1).getDay(),
getToday: () => {
const t = new Date()
return { year: t.getFullYear(), month: t.getMonth(), day: t.getDate() }
},
getYearRange: () => [2024, 2035],
toAD: d => d as ADDate,
fromAD: d => d,
startOfMonth: d => Conv.dualAD({ year: d.year, month: d.month, day: 1 }),
endOfMonth: d => {
const dim = d.month === 11 ? 31 : 30
return Conv.dualAD({ year: d.year, month: d.month, day: dim })
},
startOfYear: d => Conv.dualAD({ year: d.year, month: 0, day: 1 }),
endOfYear: d => Conv.dualAD({ year: d.year, month: 11, day: 31 }),
addDays: (d, n) => Conv.dualAD(Conv.add(d as ADDate, n)),
addMonths: (d, n) => {
let m = d.month + n
let y = d.year
while (m < 0) { m += 12; y-- }
while (m > 11) { m -= 12; y++ }
return Conv.dualAD({ year: y, month: m, day: Math.min(d.day, 30) })
},
}
registerEngine('Fiscal', fiscalEngine)📌 Date Constraints
Restrict what users can select:
import { Conv } from 'react-bs-ad-datepicker'
const minDate = Conv.dualAD(Conv.add(Conv.today().ad, -7))
const maxDate = Conv.dualAD(Conv.add(Conv.today().ad, 30))
<Calendar
type="AD"
mode="range"
minDate={minDate}
maxDate={maxDate}
disabledDays={[0, 6]}
disabledRanges={[
{ start: holidayStart, end: holidayEnd },
]}
/>📌 Theming & Dark Mode
Customize every visual aspect:
<Calendar
type="AD"
theme="dark"
themeTokens={{
primaryColor: '#0d9488',
primaryLight: '#f0fdfa',
primaryDark: '#0f766e',
backgroundColor: '#1e293b',
textColor: '#f8fafc',
radius: 'md',
cellSize: 'lg',
}}
/>📌 Controlled via Ref
Programmatic calendar control:
import { useRef } from 'react'
import type { CalRef } from 'react-bs-ad-datepicker'
function MyComponent() {
const ref = useRef<CalRef>(null)
return (
<>
<button onClick={() => ref.current?.goToToday()}>Today</button>
<button onClick={() => ref.current?.clear()}>Clear</button>
<Calendar ref={ref} type="AD" />
</>
)
}Props Reference
Core
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| type | 'AD' \| 'BS' | 'AD' | Calendar system: Gregorian (AD) or Bikram Sambat (BS) |
| mode | 'single' \| 'range' | 'single' | Selection mode |
| theme | 'light' \| 'dark' \| 'auto' | 'light' | Color scheme |
| locale | 'en' \| 'ne' | 'en' | Language — English or Nepali (नेपाली) |
| disabled | boolean | false | Disable all interaction |
Value
| Prop | Type | Description |
|------|------|-------------|
| value / defaultValue | DualDate \| null | Controlled / uncontrolled single date |
| range / defaultRange | DateRange \| null | Controlled / uncontrolled range |
| onChange | (d: DualDate) => void | Single date change callback |
| onRangeChange | (r: DateRange) => void | Range change callback |
| onStartDateChange | (d: DualDate) => void | Range start only |
| onEndDateChange | (d: DualDate \| null) => void | Range end only |
| onMonthChange | (y: number, m: number) => void | Month/year navigation callback |
| onTimeChange | (t: TimeVal) => void | Time changed |
Constraints
| Prop | Type | Description |
|------|------|-------------|
| minDate / maxDate | DualDate | Selectable date bounds |
| disabledDates | DualDate[] | Specific disabled dates |
| disabledDays | number[] | Disabled days of week (0=Sunday) |
| disabledRanges | DateRange[] | Disabled date ranges |
| isDateDisabled | (d: DualDate) => boolean | Custom disable logic |
| onBeforeSelect | (d: DualDate) => boolean \| Promise<boolean> | Gate selection |
Display
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| showToday | boolean | false | Show "Today" navigation button |
| highlightToday | boolean | false | Highlight today's cell |
| showDualDisplay | boolean | true | Show AD/BS conversion info |
| showWeekNumbers | boolean | false | Week number column |
| showPresets | boolean | false | Preset quick-select (range mode) |
| showTime | boolean | false | Show time picker |
| dualMonth | boolean | false | Show two months side by side |
| animate | boolean | false | Smooth transitions |
| variant | 'filled' \| 'outlined' \| 'ghost' | 'filled' | Visual style |
| weekStartsOn | 0 \| 1 | 0 | First day of week |
Rendering
| Prop | Type | Description |
|------|------|-------------|
| renderDay | (ctx: DayCtx) => ReactNode | Custom day cell rendering |
| renderHeader | (p: { month, year, type }) => ReactNode | Custom header |
| renderFooter | () => ReactNode | Custom footer |
| events | CalEvent[] | Events to display on the calendar |
| highlightedDates | Array<{ date: DualDate } & HighlightInfo> | Highlight specific dates |
| presetRanges | PresetRange[] | Custom presets (replaces built-in) |
| plugins | CalPlugin[] | Calendar plugins |
Popup / Portal
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| trigger | ReactNode | — | Element to open the popup calendar |
| open | boolean | — | Controlled open state |
| onOpenChange | (open: boolean) => void | — | Open state callback |
| placement | 'bottom-start' \| 'bottom-end' \| 'top-start' \| 'top-end' \| 'auto' | 'bottom-start' | Popup position |
| portal | boolean | true | Render popup in document.body |
Other
| Prop | Type | Description |
|------|------|-------------|
| engine | CalEngine | Custom calendar engine |
| shortcuts | boolean | Enable ⌘T / Escape keyboard shortcuts |
| onLoadEvents | (y: number, m: number) => Promise<CalEvent[]> | Async event loading per month |
| ariaLabel | string | ARIA label for the calendar |
| className | string | Root CSS class |
| style | CSSProperties | Inline styles |
Ref Methods (CalRef)
| Method | Description |
|--------|-------------|
| goToToday() | Navigate to today's date |
| goToDate(d: DualDate) | Navigate to a specific date |
| nextMonth() / prevMonth() | Month navigation |
| nextYear() / prevYear() | Year navigation |
| clear() | Clear current selection |
| getSelectedDate() | Get currently selected single date |
| getSelectedRange() | Get currently selected range |
| openCalendar() / closeCalendar() | Programmatic popup control |
| focus() | Focus the calendar element |
Exports
// Component
Calendar
// Types
CalendarProps, CalRef, CalType, SelMode
DualDate, ADDate, BSDate, DateRange, TimeVal
CalEvent, CalPlugin, CalEngine, CalDay
DayCtx, HighlightInfo, PresetRange, PresetContext
Tokens, Radius, CellSz, Variant, Placement
// Utilities
Conv // Date conversion & comparison utilities
registerEngine // Register a custom calendar engine
getEngine // Retrieve a registered engine by name
createPlugin // Helper to create calendar pluginsStyling
// In your app entry:
import 'react-bs-ad-datepicker/dist/calendar.css'The component uses .nc-* CSS class names with CSS custom properties generated from themeTokens. For custom styling, prefer the themeTokens prop over direct CSS overrides.
Dark Mode
Set theme="dark" or theme="auto" (follows system preference). All components adapt automatically.
BS Calendar Data — Nepali Date Conversion Engine
The library includes month-day data for Bikram Sambat years 2000–2090 based on Nepal's official calendar published by the government. All BS to AD and AD to BS conversions are computed locally — no API calls needed, works entirely offline.
- BS to AD converter — convert any Bikram Sambat date to Gregorian instantly
- AD to BS converter — convert any Gregorian date to Bikram Sambat instantly
- Epoch: BS 2000/1/1 = April 14, 1943 (Gregorian)
- Coverage: 90 years of Nepali calendar data
- Performance: O(1) conversion, all data pre-computed
TypeScript
Written in TypeScript with strict mode. Ships with complete type declarations — no need for @types/ packages.
{
"compilerOptions": {
"moduleResolution": "bundler",
"module": "esnext",
"strict": true
}
}Compatibility
| Library | Version | |---------|---------| | React | 18.x – 19.x | | TypeScript | 5.x – 6.x | | Vite | 6.x – 8.x |
License
MIT © Bibek Amatya
