@etpl/nepali-datepicker
v1.0.8
Published
Full-featured Nepali date picker for React — Bikram Sambat (BS) & Gregorian (AD) dual calendar, range selection, masked input, presets, dark mode, TypeScript support.
Maintainers
Keywords
Readme
@etpl/nepali-datepicker — Complete Documentation
A full-featured Nepali (Bikram Sambat) date picker for React with dual BS/AD calendar system, Nepali/English locale, multiple picker modes, range selection, presets, and deep customisation.
Table of Contents
- Installation
- Quick Start
- All Props — Full Reference
- Picker Modes (mode prop)
- Variants — dropdown vs inline
- Calendar Systems — BS and AD
- Language / Locale
- Selection Types
- Typeable Input (Dropdown)
- Quick Presets
- Date Constraints
- DualDateValue — Return Type
- Theming — CSS Custom Properties
- Dark Mode
- classNames Override
- Custom Rendering
- Core Utilities (exported functions)
- TypeScript Types Reference
- All CSS Class Names
- Usage Examples — Every Variant
1. Installation
npm install @etpl/nepali-datepicker
# or
yarn add @etpl/nepali-datepickerImport the component and its stylesheet:
import { NepaliDatePicker } from '@etpl/nepali-datepicker';
import '@etpl/nepali-datepicker/styles'; // or import the CSS from src/styles/index.css2. Quick Start
import { NepaliDatePicker } from '@etpl/nepali-datepicker';
import '@etpl/nepali-datepicker/styles';
function App() {
return (
<NepaliDatePicker
onChange={(val) => {
console.log(val?.formatted.bs); // "2081/04/15"
console.log(val?.formatted.ad); // "2024-07-30"
}}
/>
);
}3. All Props — Full Reference
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| variant | 'dropdown' \| 'inline' | 'dropdown' | Display variant |
| mode | PickerMode | 'date' | What the picker selects (see §4) |
| calendarSystem | 'BS' \| 'AD' | 'BS' | Primary calendar system |
| defaultCalendarSystem | 'BS' \| 'AD' | 'BS' | Uncontrolled initial calendar system |
| onCalendarSystemChange | (s: CalendarSystem) => void | — | Fires when user switches BS/AD |
| showCalendarSystemToggle | boolean | true | Show BS/AD toggle in header |
| language | 'ne' \| 'en' | 'ne' | UI language / numeral style |
| defaultLanguage | 'ne' \| 'en' | 'ne' | Uncontrolled initial language |
| onLanguageChange | (l: Language) => void | — | Fires when user switches language |
| showLanguageToggle | boolean | false | Show ne/en toggle in header |
| value | DualDateValue \| null | — | Controlled selected value |
| defaultValue | DualDateValue \| null | — | Uncontrolled initial value |
| onChange | (v: DualDateValue \| null) => void | — | Fires on date/year/month selection |
| selectionType | 'single' \| 'range' \| 'multiple' | 'single' | How dates are selected |
| startValue | DualDateValue \| null | — | Controlled range start |
| endValue | DualDateValue \| null | — | Controlled range end |
| onRangeChange | (start, end) => void | — | Fires on range selection |
| showSecondaryDate | boolean | true | Show secondary (corner) date in day cells |
| renderSecondaryDate | (cell: DualDayCell) => ReactNode | — | Custom secondary date render |
| placeholder | string | locale default | Input placeholder text |
| format | string | 'YYYY/MM/DD' | Date format string for input display |
| showTodayButton | boolean | true | Show "Today" button in footer |
| showClearButton | boolean | true | Show "Clear" button in footer |
| showWeekNumbers | boolean | false | Show week number column |
| showPresets | boolean | false | Show quick preset buttons panel |
| presets | DatePreset[] | built-in | Custom preset items |
| minDate | NepDate | — | Minimum selectable BS date |
| maxDate | NepDate | — | Maximum selectable BS date |
| disabledDates | NepDate[] | [] | Specific dates to disable |
| disableWeekend | boolean | false | Disable Saturday (and Sunday) |
| disabledDays | number[] | [] | Disable weekdays by index (0=Sun…6=Sat) |
| disabledFn | (dual: DualDateValue) => boolean | — | Programmatic disable function |
| theme | 'light' \| 'dark' \| 'system' | 'light' | Color theme |
| classNames | Partial<CalendarClassNames> | — | CSS class overrides per element |
| styles | Partial<Record<keyof CalendarClassNames, CSSProperties>> | — | Inline style overrides |
| autoClose | boolean | true | Close dropdown after selection (dropdown only) |
| position | 'auto' \| 'top' \| 'bottom' \| 'left' \| 'right' | 'auto' | Dropdown popover position |
| zIndex | number | 9999 | Popover z-index |
| disabled | boolean | false | Disable the picker entirely |
| readOnly | boolean | false | Make input non-editable (click to open still works) |
| id | string | — | HTML id for the input element |
| name | string | — | HTML name for the input element |
| ariaLabel | string | — | ARIA label for input |
| onOpen | () => void | — | Fires when dropdown opens |
| onClose | () => void | — | Fires when dropdown closes |
| onMonthChange | (year, month, system) => void | — | Fires on month navigation |
| onYearChange | (year, system) => void | — | Fires on year navigation |
| renderDay | (cell: DualDayCell) => ReactNode | — | Fully custom day cell render |
| renderHeader | (year, month, system) => ReactNode | — | Custom calendar header |
| renderFooter | () => ReactNode | — | Custom calendar footer |
4. Picker Modes (mode prop)
| Mode | Opens On | Selection | formatted.bs returns |
|------|----------|-----------|------------------------|
| 'date' (default) | Day grid | Full date | "2081/04/15" |
| 'month' | Month grid only | Month name | "04" (2-digit month index) |
| 'year' | Year/decade grid only | Year | "2081" |
| 'yearMonth' | Year grid → Month grid | Year + month | "2081/04" |
| 'monthDay' | Month grid → Day grid | Month + day | full BS date |
| 'week' | Day grid | ISO week | full BS date |
| 'quarter' | — | Quarter | — |
| 'halfYear' | — | H1/H2 | — |
Mode examples
// Year only — returns formatted.bs = "2081"
<NepaliDatePicker
mode="year"
onChange={(val) => console.log(val?.formatted.bs)} // "2081"
/>
// Month only — returns formatted.bs = "04"
<NepaliDatePicker
mode="month"
onChange={(val) => console.log(val?.formatted.bs)} // "04"
/>
// Year + Month — returns formatted.bs = "2081/04"
<NepaliDatePicker
mode="yearMonth"
onChange={(val) => console.log(val?.formatted.bs)} // "2081/04"
/>
// Full date (default)
<NepaliDatePicker
mode="date"
onChange={(val) => console.log(val?.formatted.bs)} // "2081/04/15"
/>Note: In all modes,
val.bsstill contains the full{ year, month, day }object — theformatted.bsstring is adjusted to reflect only what was selected.
5. Variants — dropdown vs inline
variant="dropdown" (default)
- Renders a text input field
- Calendar opens as a floating popover when the input is clicked/focused
- Input is typeable — type a date and the calendar navigates to it automatically (500ms debounce)
- Supported type formats:
YYYY/MM/DD,YYYY-MM-DD,YYYY.MM.DD,YYYY MM DD,YYYY/MM - Nepali digits (०–९) are also accepted
- A green ✓ / red ✕ indicator shows parse validity while typing
- Closes on: date selected +
autoClose=true, Escape key, click outside
<NepaliDatePicker variant="dropdown" />variant="inline"
- Always-visible calendar panel, no trigger input
- Fills its container width
- Ideal for booking pages, dashboards, date range UIs
<NepaliDatePicker variant="inline" />6. Calendar Systems — BS and AD
Bikram Sambat (BS) — default
<NepaliDatePicker calendarSystem="BS" />- Primary day number: BS day (large, center)
- Secondary corner: AD day (small, bottom-right)
- Header navigates BS months/years
Gregorian (AD)
<NepaliDatePicker calendarSystem="AD" language="en" />- Primary day number: AD day
- Secondary corner: BS day
- Header navigates AD months/years
Toggle in UI
<NepaliDatePicker
showCalendarSystemToggle // shows BS / AD pill in header
/>Controlled system
const [sys, setSys] = useState<CalendarSystem>('BS');
<NepaliDatePicker
calendarSystem={sys}
onCalendarSystemChange={setSys}
/>7. Language / Locale
| Value | Months | Day headers | Numbers | Labels |
|-------|--------|-------------|---------|--------|
| 'ne' | बैशाख, जेष्ठ… | आ, सो, म… | Nepali ०–९ | Nepali |
| 'en' | Baisakh, Jestha… | Su, Mo, Tu… | Arabic 0–9 | English |
<NepaliDatePicker language="ne" /> // Nepali (default)
<NepaliDatePicker language="en" /> // English
// Toggle in header
<NepaliDatePicker showLanguageToggle />
// Controlled
const [lang, setLang] = useState<Language>('ne');
<NepaliDatePicker language={lang} onLanguageChange={setLang} />8. Selection Types
Single (default)
<NepaliDatePicker
selectionType="single"
onChange={(val) => console.log(val)}
/>Range
<NepaliDatePicker
selectionType="range"
variant="inline"
onRangeChange={(start, end) => {
console.log(start?.formatted.bs, end?.formatted.bs);
}}
/>Click first date = range start, click second = range end. Range highlights cells between start and end with hover preview.
Multiple
<NepaliDatePicker selectionType="multiple" />9. Masked Input (Dropdown)
The dropdown input uses a slot-by-slot masked input driven by the format prop. The mask is shaped exactly like the format string — you type only digits and separators are auto-inserted.
How it works
Format: YYYY/MM/DD
Mask: ____/__/__
Type "2": 2___/__/__
Type "0": 20__/__/__
Type "8": 208_/__/__
Type "1": 2081/__/__ ← year complete, cursor jumps to MM slot
Type "0": 2081/0_/__
Type "4": 2081/04/__ ← month complete
Type "1": 2081/04/1_
Type "5": 2081/04/15 ✓ ← onChange fires immediately!Key behaviour
- Digits only — only
0–9keys are accepted (Nepali digits ०–९ are also normalised) - onChange fires immediately when the last digit slot is filled and the date is valid — no need to click a day in the calendar
- Cursor stays at the typed position — does not jump to the end after each keystroke
- Arrow keys move the caret left/right among digit slots
- Backspace removes the digit at caret position and shifts later digits left
- Delete removes the digit at the cursor position
- Paste extracts digits from the pasted string and fills the mask from the beginning
- Click-outside closes the popover but keeps the typed value — no revert to previous date
- For
mode="date": after mask completes, the calendar opens so the user can optionally pick a different day - For
mode="year",mode="month",mode="yearMonth": mask completion closes the picker immediately (no day grid needed)
Supported formats
Any format built from Y, M, D tokens and any separator:
| Format | Mask | Example filled |
|--------|------|----------------|
| YYYY/MM/DD | ____/__/__ | 2081/04/15 |
| DD/MM/YYYY | __/__/____ | 15/04/2081 |
| MM/DD/YYYY | __/__/____ | 04/15/2081 |
| YYYY-MM-DD | ____-__-__ | 2081-04-15 |
| YYYY.MM.DD | ____.__.__ | 2081.04.15 |
| YYYY/MM | ____/__ | 2081/04 |
| MM/YYYY | __/____ | 04/2081 |
| YYYY | ____ | 2081 |
Return value matches format
formatted.bs always uses the format string exactly:
// format="DD/MM/YYYY"
onChange={(val) => {
console.log(val?.formatted.bs); // "15/04/2081"
console.log(val?.formatted.ad); // "30/07/2024"
}}
// format="YYYY-MM-DD"
onChange={(val) => {
console.log(val?.formatted.bs); // "2081-04-15"
console.log(val?.formatted.ad); // "2024-07-30"
}}
// format="YYYY/MM" + mode="yearMonth"
onChange={(val) => {
console.log(val?.formatted.bs); // "2081/04"
console.log(val?.formatted.ad); // "2024/07"
}}Both
formatted.bsandformatted.adalways mirror the same format pattern.
Disable typing (readonly input)
<NepaliDatePicker readOnly />
// Input opens calendar on click but does not accept keyboard input10. Quick Presets
<NepaliDatePicker showPresets />Built-in presets (language-aware):
| English label | Nepali label | |---------------|--------------| | Today | आज | | Yesterday | हिजो | | Tomorrow | भोली | | Last 7 Days | गत ७ दिन | | Last 14 Days | गत १४ दिन | | Last 30 Days | गत ३० दिन | | This Month | यो महिना | | This Year | यो वर्ष |
Custom presets
import { makeDualDateValue, getNepaliToday } from '@etpl/nepali-datepicker';
<NepaliDatePicker
showPresets
presets={[
{
label: 'Dashain',
getValue: () => makeDualDateValue({ year: 2081, month: 7, day: 10 }),
},
{
label: 'New Year',
getValue: () => makeDualDateValue({ year: 2082, month: 1, day: 1 }),
},
]}
/>11. Date Constraints
Min / Max date
<NepaliDatePicker
minDate={{ year: 2081, month: 1, day: 1 }}
maxDate={{ year: 2081, month: 12, day: 30 }}
/>Disable specific dates
<NepaliDatePicker
disabledDates={[
{ year: 2081, month: 4, day: 10 },
{ year: 2081, month: 4, day: 11 },
]}
/>Disable weekends
<NepaliDatePicker disableWeekend />Disable specific weekdays
// Disable Mondays (1) and Fridays (5)
<NepaliDatePicker disabledDays={[1, 5]} />
// 0=Sun, 1=Mon, 2=Tue, 3=Wed, 4=Thu, 5=Fri, 6=Sat12. DualDateValue — Return Type
Every onChange always emits a DualDateValue containing both BS and AD dates:
interface DualDateValue {
bs: {
year: number; // e.g. 2081
month: number; // 1–12
day: number; // 1–32
};
ad: Date; // JavaScript Date object (Gregorian)
formatted: {
bs: string; // "2081/04/15" (or mode-adjusted: "2081", "04", "2081/04")
ad: string; // "2024-07-30"
};
}Accessing values
onChange={(val) => {
if (!val) return; // null = cleared
// BS date parts
const { year, month, day } = val.bs;
// AD JavaScript Date
const adDate = val.ad;
const adYear = adDate.getFullYear();
// Formatted strings
console.log(val.formatted.bs); // "2081/04/15"
console.log(val.formatted.ad); // "2024-07-30"
}}Mode-adjusted formatted.bs
| Mode | formatted.bs |
|------|----------------|
| date | "2081/04/15" |
| year | "2081" |
| month | "04" |
| yearMonth | "2081/04" |
The full
val.bsobject always hasyear,month,dayregardless of mode.
13. Theming — CSS Custom Properties
All visual tokens are exposed as CSS custom properties on :root. Override any of them in your own CSS:
:root {
/* ── Brand / Primary ──────────────────────────────── */
--ndc-primary: hsl(174, 52%, 38%); /* teal-green */
--ndc-primary-hover: hsl(174, 52%, 28%);
--ndc-primary-light: hsl(174, 50%, 94%); /* light tint for hover bg */
/* ── Surfaces ─────────────────────────────────────── */
--ndc-surface: hsl(0, 0%, 100%); /* calendar background */
--ndc-surface-hover: hsl(174, 20%, 96%); /* day cell hover bg */
/* ── Borders ──────────────────────────────────────── */
--ndc-border: hsl(210, 16%, 90%);
/* ── Text ─────────────────────────────────────────── */
--ndc-text: hsl(215, 28%, 17%); /* primary text */
--ndc-text-muted: hsl(215, 12%, 52%); /* weekday headers, muted */
--ndc-text-secondary: hsl(215, 10%, 70%); /* secondary corner date */
/* ── Today indicator (dot + accent text) ─────────── */
--ndc-today-bg: transparent;
--ndc-today-text: hsl(174, 52%, 32%); /* today number color */
--ndc-today-dot: hsl(174, 52%, 42%); /* dot under today number */
/* ── Selected day ─────────────────────────────────── */
--ndc-selected-bg: hsl(174, 52%, 38%);
--ndc-selected-text: hsl(0, 0%, 100%);
/* ── Range selection ──────────────────────────────── */
--ndc-range-bg: hsl(174, 45%, 90%);
--ndc-range-text: hsl(174, 52%, 25%);
/* ── Weekend day ──────────────────────────────────── */
--ndc-weekend: hsl(355, 60%, 58%); /* soft rose */
/* ── Disabled days ────────────────────────────────── */
--ndc-disabled: hsl(215, 10%, 78%);
--ndc-disabled-bg: hsl(215, 10%, 97%);
/* ── Header ───────────────────────────────────────── */
--ndc-header-bg: hsl(215, 28%, 20%); /* dark slate */
--ndc-header-text: hsl(0, 0%, 97%);
/* ── Toggle pills ─────────────────────────────────── */
--ndc-toggle-bg: hsl(210, 18%, 94%);
/* ── Border radius ────────────────────────────────── */
--ndc-radius: 12px; /* calendar corners */
--ndc-radius-sm: 7px; /* day cell corners */
/* ── Shadow ───────────────────────────────────────── */
--ndc-shadow: 0 8px 32px rgba(0,0,0,0.08), 0 2px 8px rgba(0,0,0,0.04);
/* ── Cell sizes ───────────────────────────────────── */
--ndc-cell-size: 2.6rem; /* dropdown day cell */
--ndc-cell-size-inline: 3.4rem; /* inline day cell */
/* ── Typography ───────────────────────────────────── */
--ndc-primary-day-size: 0.9rem; /* main day number */
--ndc-secondary-day-size: 0.52rem; /* corner date number */
--ndc-font: "Inter", "Segoe UI", system-ui, sans-serif;
}Example: Change to indigo theme
:root {
--ndc-primary: hsl(245, 70%, 55%);
--ndc-primary-hover: hsl(245, 70%, 45%);
--ndc-primary-light: hsl(245, 70%, 95%);
--ndc-today-text: hsl(245, 70%, 45%);
--ndc-today-dot: hsl(245, 70%, 55%);
--ndc-selected-bg: hsl(245, 70%, 55%);
--ndc-header-bg: hsl(245, 70%, 55%);
--ndc-range-bg: hsl(245, 70%, 93%);
}Example: Change cell size for compact layout
:root {
--ndc-cell-size: 2rem;
--ndc-primary-day-size: 0.78rem;
--ndc-secondary-day-size: 0.45rem;
}14. Dark Mode
Automatic via theme prop
<NepaliDatePicker theme="dark" />
<NepaliDatePicker theme="light" />
<NepaliDatePicker theme="system" /> // follows prefers-color-schemeManual via data-ndc-theme attribute
<!-- Wrap your app or the picker in a container with: -->
<div data-ndc-theme="dark">
<!-- picker here -->
</div>Dark mode CSS tokens (auto-applied)
[data-ndc-theme="dark"] {
--ndc-primary: hsl(174, 55%, 50%);
--ndc-surface: hsl(220, 26%, 10%);
--ndc-border: hsl(220, 18%, 20%);
--ndc-text: hsl(210, 18%, 90%);
--ndc-header-bg: hsl(220, 26%, 14%);
/* ... all tokens are defined for dark mode */
}15. classNames Override
Every element has a named slot you can inject custom classes into (works with Tailwind CSS):
<NepaliDatePicker
classNames={{
container: "relative",
input: "border-2 border-teal-400 rounded-xl px-4 py-2",
inputWrapper: "relative",
calendar: "rounded-3xl shadow-2xl",
header: "bg-gradient-to-r from-teal-600 to-emerald-600 text-white",
headerTitle: "font-bold text-lg",
headerNav: "hover:bg-white/20 rounded-lg",
calendarSystemToggle: "text-xs px-2 py-1 rounded-full",
languageToggle: "text-xs px-2 py-1 rounded-full",
weekdayRow: "",
weekdayCell: "text-teal-500 font-semibold",
grid: "",
dayCell: "rounded-xl hover:bg-teal-50 transition-colors",
dayPrimary: "font-semibold",
daySecondary: "text-gray-300",
selectedDay: "bg-teal-600 text-white shadow-lg",
todayDay: "text-teal-600 font-bold",
rangeDay: "bg-teal-100",
rangeStart: "rounded-l-xl bg-teal-600",
rangeEnd: "rounded-r-xl bg-teal-600",
disabledDay: "opacity-30 cursor-not-allowed",
weekendDay: "text-rose-500",
outsideMonthDay: "opacity-20",
monthCell: "rounded-lg hover:bg-teal-50",
yearCell: "rounded-lg hover:bg-teal-50",
presetPanel: "border-t border-gray-100",
presetItem: "rounded-full text-xs",
footer: "border-t border-gray-100",
todayButton: "text-teal-600 font-medium",
clearButton: "text-gray-400",
}}
/>16. Custom Rendering
Custom day cell
<NepaliDatePicker
renderDay={(cell) => (
<div className="relative flex items-center justify-center w-full h-full">
<span className={cell.isToday ? "text-red-500 font-bold" : ""}>
{cell.bsDay}
</span>
{cell.isWeekend && <div className="absolute bottom-1 w-1 h-1 bg-red-400 rounded-full" />}
</div>
)}
/>Custom secondary corner date
<NepaliDatePicker
showSecondaryDate
renderSecondaryDate={(cell) => (
<span style={{ fontSize: '0.45rem', color: 'purple' }}>
{cell.adDay}
</span>
)}
/>Custom header
<NepaliDatePicker
renderHeader={(year, month, system) => (
<div className="flex items-center justify-between p-3 bg-rose-600 text-white">
<span>{system} · {month}/{year}</span>
</div>
)}
/>Custom footer
<NepaliDatePicker
renderFooter={() => (
<div className="p-2 text-center text-xs text-gray-400">
Select a date above
</div>
)}
/>17. Core Utilities (exported functions)
All core functions are exported and can be used independently:
import {
getNepaliDate,
getEnglishDate,
getNepaliToday,
getBaar,
getTotalDays,
compareBs,
bsEquals,
bsIsBetween,
makeDualDateValue,
makeDualDateValueFromAd,
toNepaliDigits,
fromNepaliDigits,
nepDateToString,
nepDateFromString,
toLongBsDateString,
toLongAdDateString,
} from '@etpl/nepali-datepicker';| Function | Signature | Description |
|----------|-----------|-------------|
| getNepaliDate | (adDate: Date) => NepDate | Convert JS Date → BS date |
| getEnglishDate | (bs: NepDate) => Date | Convert BS date → JS Date |
| getNepaliToday | () => NepDate | Get today's BS date |
| getBaar | (year, month) => number | Get day-of-week for BS month start (1=Sun…7=Sat) |
| getTotalDays | (year, month) => number | Days in a BS month (29–32) |
| compareBs | (a, b) => -1 \| 0 \| 1 | Compare two BS dates |
| bsEquals | (a, b) => boolean | Check if two BS dates are equal |
| bsIsBetween | (date, start, end) => boolean | Check if date is in range |
| makeDualDateValue | (bs: NepDate) => DualDateValue | Build a DualDateValue from BS |
| makeDualDateValueFromAd | (ad: Date) => DualDateValue | Build a DualDateValue from AD |
| toNepaliDigits | (n: number \| string) => string | 15 → १५ |
| fromNepaliDigits | (s: string) => string | "१५" → "15" |
| nepDateToString | (date, format?) => string | Format BS date string |
| nepDateFromString | (str: string) => NepDate \| null | Parse BS date string |
| toLongBsDateString | (date, lang) => string | "२०८१ साल बैशाख १५ गते" |
| toLongAdDateString | (date, lang) => string | "July 30, 2024" |
Examples
import { getNepaliDate, toNepaliDigits, makeDualDateValue } from '@etpl/nepali-datepicker';
// Today in BS
const today = getNepaliDate(new Date());
console.log(today); // { year: 2081, month: 4, day: 15 }
// Nepali digits
console.log(toNepaliDigits(2081)); // "२०८१"
// Build dual value
const dual = makeDualDateValue({ year: 2081, month: 4, day: 15 });
console.log(dual.formatted.bs); // "2081/04/15"
console.log(dual.formatted.ad); // "2024-07-30"18. TypeScript Types Reference
// Calendar system
type CalendarSystem = 'BS' | 'AD';
// UI language
type Language = 'ne' | 'en';
// Picker display variant
type PickerVariant = 'dropdown' | 'inline';
// Picker mode
type PickerMode =
| 'date' // full date
| 'month' // month only
| 'year' // year only
| 'yearMonth' // year + month
| 'monthDay' // month + day
| 'week'
| 'quarter'
| 'halfYear';
// Selection behaviour
type SelectionType = 'single' | 'range' | 'multiple';
// BS date object
interface NepDate {
year: number;
month: number;
day: number;
}
// What onChange emits — always has BOTH BS and AD
interface DualDateValue {
bs: NepDate;
ad: Date;
formatted: {
bs: string; // mode-adjusted
ad: string;
};
}
// Single day cell in the grid
interface DualDayCell {
bsDay: number; bsMonth: number; bsYear: number;
adDay: number; adMonth: number; adYear: number;
isCurrentMonth: boolean;
isToday: boolean;
isSelected: boolean;
isInRange: boolean;
isRangeStart: boolean;
isRangeEnd: boolean;
isDisabled: boolean;
isWeekend: boolean;
weekdayIndex: number; // 0=Sun … 6=Sat
}
// Custom preset item
interface DatePreset {
label: string;
getValue: () => DualDateValue | [DualDateValue, DualDateValue] | null;
}
// classNames map — all customisable slots
interface CalendarClassNames {
container: string;
input: string;
inputWrapper: string;
calendar: string;
header: string;
headerTitle: string;
headerNav: string;
calendarSystemToggle: string;
languageToggle: string;
weekdayRow: string;
weekdayCell: string;
grid: string;
dayCell: string;
dayPrimary: string;
daySecondary: string;
selectedDay: string;
todayDay: string;
rangeDay: string;
rangeStart: string;
rangeEnd: string;
disabledDay: string;
weekendDay: string;
outsideMonthDay: string;
monthCell: string;
yearCell: string;
presetPanel: string;
presetItem: string;
footer: string;
todayButton: string;
clearButton: string;
}19. All CSS Class Names
These are the generated class names on rendered HTML elements. You can target them directly in your stylesheet:
| Class | Element |
|-------|---------|
| .ndc-calendar | Root calendar wrapper |
| .ndc-inline | Added when variant="inline" |
| .ndc-header | Header bar |
| .ndc-header-center | Middle section of header |
| .ndc-header-title | Month/year title button |
| .ndc-header-toggles | Toggle pills wrapper |
| .ndc-nav-btn | Prev/next navigation buttons |
| .ndc-toggle-pill | BS/AD or ne/en pill container |
| .ndc-toggle-option | Individual option within pill |
| .ndc-toggle-option.active | Currently active option |
| .ndc-weekday-row | Row of weekday abbreviations |
| .ndc-weekday-cell | Single weekday abbreviation cell |
| .ndc-grid | Day/month/year grid container |
| .ndc-day-cell | Individual day cell |
| .ndc-day-cell.today | Today's cell |
| .ndc-day-cell.selected | Selected day cell |
| .ndc-day-cell.in-range | Day within a range |
| .ndc-day-cell.range-start | Range start day |
| .ndc-day-cell.range-end | Range end day |
| .ndc-day-cell.weekend | Weekend day |
| .ndc-day-cell.disabled | Disabled day |
| .ndc-day-cell.outside | Day from prev/next month |
| .ndc-day-primary | Primary (large) day number |
| .ndc-day-secondary | Secondary corner date |
| .ndc-month-grid | Month picker grid |
| .ndc-month-cell | Single month button |
| .ndc-month-cell.active | Selected month |
| .ndc-year-grid | Year picker grid |
| .ndc-year-cell | Single year button |
| .ndc-year-cell.active | Selected year |
| .ndc-year-cell.current | Current year (today) |
| .ndc-footer | Footer bar |
| .ndc-footer-btn | Footer button base |
| .ndc-footer-btn.today | Today button |
| .ndc-footer-btn.clear | Clear button |
| .ndc-selected-display | Inline: selected date display strip |
| .ndc-dropdown-wrapper | Dropdown: outer wrapper |
| .ndc-input-wrapper | Dropdown: input container |
| .ndc-input | Dropdown: text input |
| .ndc-input--valid | Input with valid typed date |
| .ndc-input--invalid | Input with invalid typed text |
| .ndc-input-icon | Calendar icon in input |
| .ndc-input-status | ✓ / ✕ validation indicator |
| .ndc-input-status--valid | Green ✓ indicator |
| .ndc-input-status--invalid | Red ✕ indicator |
| .ndc-popover | Dropdown: floating panel |
| .ndc-popover.pos-top | Popover opens upward |
| .ndc-presets | Presets panel container |
| .ndc-preset-btn | Individual preset button |
| .ndc-preset-item | Alternative preset item style |
20. Usage Examples — Every Variant
A. Basic dropdown
<NepaliDatePicker onChange={(v) => console.log(v?.formatted.bs)} />B. Inline full calendar
<NepaliDatePicker variant="inline" onChange={(v) => console.log(v)} />C. Year-only picker
<NepaliDatePicker
mode="year"
onChange={(v) => console.log(v?.formatted.bs)} // "2081"
/>D. Month-only picker
<NepaliDatePicker
mode="month"
onChange={(v) => console.log(v?.formatted.bs)} // "04"
/>E. Year + Month picker
<NepaliDatePicker
mode="yearMonth"
onChange={(v) => console.log(v?.formatted.bs)} // "2081/04"
/>F. Date range (inline)
<NepaliDatePicker
variant="inline"
selectionType="range"
onRangeChange={(start, end) => {
console.log(start?.formatted.bs, end?.formatted.bs);
}}
/>G. AD calendar, English language
<NepaliDatePicker
calendarSystem="AD"
language="en"
onChange={(v) => console.log(v?.formatted.ad)}
/>H. Controlled value
const [val, setVal] = useState<DualDateValue | null>(null);
<NepaliDatePicker
value={val}
onChange={setVal}
/>I. With presets panel
<NepaliDatePicker
variant="inline"
showPresets
onChange={(v) => console.log(v)}
/>J. With constraints
<NepaliDatePicker
minDate={{ year: 2081, month: 1, day: 1 }}
maxDate={{ year: 2081, month: 12, day: 30 }}
disableWeekend
/>K. Dark mode
<NepaliDatePicker theme="dark" />L. Typeable dropdown with read-only toggle
// Editable (default):
<NepaliDatePicker variant="dropdown" />
// Read-only (click to open, no typing):
<NepaliDatePicker variant="dropdown" readOnly />M. Fully custom styled with Tailwind
<NepaliDatePicker
classNames={{
calendar: "rounded-3xl shadow-2xl border-0",
header: "bg-gradient-to-r from-violet-600 to-indigo-600 text-white rounded-t-3xl px-4 py-3",
dayCell: "rounded-xl transition-all hover:scale-105",
selectedDay: "bg-violet-600 text-white shadow-lg",
weekendDay: "text-rose-400",
footer: "bg-gray-50 border-t border-gray-100",
}}
/>N. React Hook Form integration
import { Controller } from 'react-hook-form';
<Controller
name="nepaliDate"
control={control}
render={({ field }) => (
<NepaliDatePicker
value={field.value}
onChange={field.onChange}
/>
)}
/>O. Secondary date (dual-date cells)
// Show corner date (default: true)
<NepaliDatePicker showSecondaryDate />
// Hide corner date for clean look
<NepaliDatePicker showSecondaryDate={false} />
// Custom corner render
<NepaliDatePicker
showSecondaryDate
renderSecondaryDate={(cell) => <span>{cell.adDay}</span>}
/>P. Both toggles visible
<NepaliDatePicker
showCalendarSystemToggle // BS / AD in header
showLanguageToggle // ne / en in header
/>Q. Format string
<NepaliDatePicker format="DD-MM-YYYY" /> // shows "15-04-2081"
<NepaliDatePicker format="YYYY/MM/DD" /> // default "2081/04/15"R. Position control (dropdown)
<NepaliDatePicker position="top" /> // opens above input
<NepaliDatePicker position="bottom" /> // opens below (default)
<NepaliDatePicker position="auto" /> // auto-detects