dayfold
| Install | |
|---|---|
npm install dayfold |
|
| Latest Version: | 0.1.0 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Sep 29, 2026 |
| Links: | GitHub · npm |
dayfold
An accessible, headless date picker for React, Vue and plain JavaScript — with Hijri, Persian and every other Intl calendar built in, in about 7.5 kB and zero dependencies.
dayfold handles the hard parts of a date picker — calendar math, keyboard navigation, ARIA, focus management, screen-reader announcements — and lets you render any markup with any styling. If you'd rather not build the markup, an optional ready-made <DateField> is included.
Live demos & docs · API reference · العربية · GitHub
Contents
- Why dayfold
- Comparison
- Installation
- Quick start — ready-made field · React hook · Vue · Vanilla JS
DateFieldprops- Picker options
- Returned API
- Prop getters
- Calendar data
- Guides — disabled dates · linked start & end fields · range & multiple · month & year dropdowns · text input · Hijri & other calendars · styling · forms, SSR & SEO
- Accessibility
- Keyboard
- Browser support
- Entry points & sizes
- FAQ
Why dayfold
| Headless | You get state and prop getters for your own elements. Works with Tailwind, CSS Modules, styled-components, any design system — there is nothing to override. |
| Accessible by default | Follows the W3C APG date-picker dialog and grid patterns with a real <button> in every cell, roving focus, polite live announcements, dialog focus trap and RTL-aware arrow keys. Tested with axe-core. |
| Every calendar, no extra weight | Hijri (Umm al-Qura), Persian, Hebrew, Buddhist, Japanese… are computed from the browser's built-in Intl data, so they cost 0 extra bytes and need no add-on package. Show a second calendar under each day (e.g. Hijri under Gregorian). |
| Every string is yours | Every aria-label, announcement and placeholder can be overridden per instance. Arabic ships built in. |
| Tiny | ~7.5 kB min+gzip for the complete picker: single / range / multiple selection, popup, text input, month & year dropdowns. Zero dependencies, tree-shakeable. |
| Framework-agnostic | One core with thin adapters: React 18+, Vue 3.5+, or plain DOM. |
| Forms & SEO ready | Hidden inputs for native <form> posts, <time datetime> props, SSR-safe ids, and a fixed 6-week grid that never shifts layout. |
| Modern dates | Values are plain ISO strings ("2026-09-29") — no time-zone bugs. Accepts Date, ISO strings and Temporal.PlainDate. |
Comparison
Measured in September 2026. Sizes are minified + gzipped JavaScript as a consumer bundles it (esbuild / Bundlephobia); styles for the other libraries are extra.
| dayfold | cally | react-day-picker | flatpickr | react-datepicker | |
|---|---|---|---|---|---|
| JS size (min+gzip) | 7.5 kB | 9.2 kB | 18.9 kB | 14.8 kB | 46.7 kB |
| Dependencies | 0 | 1 | 2 | 0 | 3 |
| Frameworks | React, Vue, vanilla | Web component | React | Vanilla | React |
| Headless (your markup) | Yes | Partly (parts / CSS vars) | Partly (class names, components) | No | No |
| Input + popup included | Yes | No | No (grid only) | Yes | Yes |
| Hijri / Persian / Hebrew | Built in (Intl) | Not documented | Separate @daypicker/* add-ons |
Not built in | Not built in |
| Month & year dropdowns | Yes | — | Yes | Month only | Yes |
| Declarative disabled rules | Yes | — | Yes | Yes | Yes |
| Every a11y string overridable | Yes | Partly | Yes | Partly | Partly |
| Time picking | No (dates only) | No | No | Yes | Yes |
Where others are stronger: react-day-picker has a larger ecosystem (it powers the shadcn/ui calendar); flatpickr and react-datepicker include time selection, which dayfold does not (yet). If you need a time picker today, pair dayfold with a time input or use one of those.
Installation
npm install dayfold
# or
pnpm add dayfold
# or
yarn add dayfold
React (18+) and Vue (3.5+) are optional peer dependencies — install whichever you use. Nothing else is installed.
Quick start
1. Ready-made field (React)
The fastest way: an accessible, styled field you can still customise.
import { useState } from 'react'
import { DateField } from 'dayfold/react/field'
import 'dayfold/field.css' // optional default look
export function BookingForm() {
const [date, setDate] = useState<string | null>(null)
return (
<DateField
label="Appointment date"
value={date}
onValueChange={setDate}
disabled={{ before: new Date() }} // no past dates
iconPosition="start" // 'start' | 'end'
name="appointment" // posts "2026-09-29" with the form
/>
)
}
2. Headless React hook
Full control of the markup:
import { useDatePicker } from 'dayfold/react'
export function Calendar() {
const dp = useDatePicker({ locale: 'en-US' })
return (
<div {...dp.getRootProps()}>
<button {...dp.getPrevButtonProps()}>‹</button>
<button {...dp.getNextButtonProps()}>›</button>
{dp.months.map((month) => (
<table key={month.start} {...dp.getGridProps(month)}>
<caption {...dp.getMonthLabelProps(month)}>{month.label}</caption>
<thead>
<tr>
{dp.weekdays.map((w) => (
<th key={w.weekday} {...dp.getWeekdayProps(w)}>{w.narrow}</th>
))}
</tr>
</thead>
<tbody>
{month.weeks.map((week) => (
<tr key={week[0].date} {...dp.getWeekProps()}>
{week.map((day) => (
<td key={day.date} {...dp.getCellProps(day)}>
<button {...dp.getDayProps(day)}>{day.label}</button>
</td>
))}
</tr>
))}
</tbody>
</table>
))}
<p>Selected: {dp.valueText ?? 'none'}</p>
</div>
)
}
3. Vue
<script setup>
import { useDatePicker } from 'dayfold/vue'
// Options can be an object, a ref, or a getter — changes are picked up reactively.
const dp = useDatePicker({ locale: 'ar-SA', calendar: 'islamic-umalqura' })
</script>
<template>
<div v-bind="dp.getRootProps()">
<button v-bind="dp.getPrevButtonProps()">‹</button>
<button v-bind="dp.getNextButtonProps()">›</button>
<table v-for="month in dp.months.value" :key="month.start" v-bind="dp.getGridProps(month)">
<caption v-bind="dp.getMonthLabelProps(month)">{{ month.label }}</caption>
<tr v-for="week in month.weeks" :key="week[0].date" v-bind="dp.getWeekProps()">
<td v-for="day in week" :key="day.date" v-bind="dp.getCellProps(day)">
<button v-bind="dp.getDayProps(day)">{{ day.label }}</button>
</td>
</tr>
</table>
</div>
</template>
4. Vanilla JavaScript
import { createDatePicker } from 'dayfold'
import { h } from 'dayfold/dom'
const dp = createDatePicker({ locale: 'fa-IR', calendar: 'persian' })
const root = document.querySelector('#calendar')
function render() {
const [month] = dp.getMonths()
root.replaceChildren(
h('table', dp.getGridProps(month),
h('caption', dp.getMonthLabelProps(month), month.label),
...month.weeks.map((week) =>
h('tr', dp.getWeekProps(),
...week.map((day) =>
h('td', dp.getCellProps(day), h('button', dp.getDayProps(day), day.label)))))),
)
}
dp.subscribe(render)
render()
Focus is restored to the right day after every render, so a full re-render like this stays keyboard-friendly. Update options later with dp.update({ ...options }).
DateField props
import { DateField } from 'dayfold/react/field' — accepts every picker option plus:
| Prop | Type | Default | Description |
|---|---|---|---|
label |
ReactNode |
— (required) | Visible label, associated with the input. |
hideLabel |
boolean |
false |
Hide the label visually but keep it for screen readers. |
description |
ReactNode |
— | Hint below the field, linked with aria-describedby. |
error |
ReactNode |
— | Error text; sets aria-invalid and is linked with aria-describedby. |
icon |
ReactNode | false |
calendar icon | Content of the trigger button — any SVG, icon-library component, emoji or text. false removes the trigger. |
iconPosition |
'start' | 'end' |
'end' |
Where the trigger sits. Changes DOM order (so Tab order matches) and mirrors automatically in RTL. |
dropdowns |
boolean |
true |
Month and year <select>s in the popup header. |
prevIcon / nextIcon |
ReactNode |
chevrons | Icons for the month navigation buttons. |
renderDay |
(day: CalendarDay) => ReactNode |
day number | Custom day content (the accessible name still comes from labels.day). |
inputProps |
InputHTMLAttributes |
— | Extra input attributes: required, autoFocus, className, … |
className |
string |
— | Added to the root element. |
classNames |
Partial<Record<Part, string>> |
— | Class per part: root, label, description, error, control, input, trigger, popover, header, selects, select, nav, navButton, months, grid, weekday, cell, day. |
Every part also has a stable dayfold-* class (e.g. .dayfold-trigger), and the root carries data-icon-position, data-open and data-invalid.
<DateField label="Start date" icon={<CalendarDays size={18} />} iconPosition="start" />
<DateField label="Check-in" icon={<span aria-hidden="true">📅</span>} />
<DateField label="Date of birth" icon={false} placeholder="dd/mm/yyyy" />
<DateField label="Date" classNames={{ input: 'input input-bordered', day: 'btn btn-ghost' }} />
Theming field.css — every value is a custom property; light / dark is automatic:
.my-form .dayfold-field {
--dayfold-accent: #0f766e;
--dayfold-on-accent: #fff;
--dayfold-accent-soft: #ccfbf1;
--dayfold-bg: #fff;
--dayfold-fg: #111;
--dayfold-muted: #555;
--dayfold-border: #ccc;
--dayfold-danger: #b42318;
--dayfold-focus: #0f766e;
--dayfold-radius: 12px;
--dayfold-day-size: 44px;
}
Picker options
Used by useDatePicker() (React / Vue), createDatePicker() (vanilla) and <DateField>.
Selection
| Option | Type | Default | Description |
|---|---|---|---|
mode |
'single' | 'range' | 'multiple' |
'single' |
Selection mode. |
value |
see below | — | Controlled value. Pass null (or []) for "nothing selected". |
defaultValue |
see below | — | Initial value for uncontrolled use. |
onValueChange |
(value, { date, source }) => void |
— | Called on every change. source: 'click' | 'keyboard' | 'input' | 'clear' | 'api'. |
maxSelections |
number |
— | Multiple mode: maximum number of dates. |
allowDisabledInRange |
boolean |
false |
Range mode: allow a range to span disabled dates. |
Values are always returned as ISO strings: string | null (single), string[] (multiple), { start, end } | null (range). Inputs also accept Date and Temporal.PlainDate.
Restricting dates
| Option | Type | Default | Description |
|---|---|---|---|
min / max |
date | — | Earliest / latest selectable date. Also stops navigation and trims the dropdowns. |
disabled |
DateMatcher | DateMatcher[] |
— | Dates that can't be selected — see disabling dates. |
isDateDisabled |
(iso: string) => boolean |
— | Function form (same as a function inside disabled). |
Calendar & locale
| Option | Type | Default | Description |
|---|---|---|---|
locale |
BCP 47 tag | runtime locale | Formatting, week start, weekend and direction, e.g. 'en-US', 'ar-SA'. |
calendar |
calendar id | 'gregory' |
'islamic-umalqura', 'islamic-civil', 'persian', 'hebrew', 'buddhist', 'japanese'… |
secondaryCalendar |
calendar id | — | Second calendar shown under each day. |
numberingSystem |
'latn' | 'arab' | … |
from locale | Digits to display. |
dir |
'ltr' | 'rtl' |
from locale | Writing direction (also flips arrow keys). |
weekStartsOn |
0–6 |
from locale | First day of the week (0 = Sunday). |
Display & navigation
| Option | Type | Default | Description |
|---|---|---|---|
numberOfMonths |
number |
1 |
Months shown side by side. |
fixedWeeks |
boolean |
true |
Always 6 rows, so the grid never changes height (no layout shift). |
years |
{ from?, to? } |
min/max, else −100 / +50 |
Year range for the year dropdown, in the calendar's own numbering. |
defaultFocusedDate |
date | selection, then today | Initially focused / visible date. |
today |
date | local today | Override "today" (tests, SSR). |
Popup
| Option | Type | Default | Description |
|---|---|---|---|
open / defaultOpen |
boolean |
false |
Controlled / initial popup state. |
onOpenChange |
(open) => void |
— | Called when the popup opens or closes. |
closeOnSelect |
boolean |
true |
Close after picking a date (or a full range). |
closeOnOutsideClick |
boolean |
true |
Close on pointer-down outside the popup. |
modal |
boolean |
true |
Trap Tab inside the popup. |
Text input & forms
| Option | Type | Default | Description |
|---|---|---|---|
inputFormat |
Intl.DateTimeFormatOptions |
numeric y/m/d | How the value is shown in the input. |
parse |
(text, { locale, calendar, today }) => iso | null |
locale-aware | Custom parser. Use withShortcuts() for "tomorrow", "+3d"… |
placeholder |
string |
e.g. mm/dd/yyyy |
Input placeholder. |
name |
string |
— | Field name for getHiddenInputProps() / DateField. |
Accessibility
| Option | Type | Default | Description |
|---|---|---|---|
labels |
Partial<Labels> |
English | Override any accessible string — see labels. |
announce |
'auto' | 'manual' | false |
'auto' |
'auto' uses a shared live region; 'manual' exposes state.announcement for your own. |
id |
string |
auto | Stable id prefix (pass one for SSR if not using the React / Vue adapters). |
focusDay |
(iso) => void |
built in | Custom focus routine if you don't render data-date attributes. |
Returned API
| Member | Description |
|---|---|
months / getMonths() |
Visible months, each with label, weeks of CalendarDay and more. |
weekdays / getWeekdays() |
Weekday names in display order (narrow, short, long). |
value / getValue() |
Effective value (controlled or not). |
valueText / getValueText() |
Localised text, e.g. "Sep 29 – Oct 3, 2026". |
state / getState() |
focusedDate, visibleDate, open, inputText, inputInvalid, announcement. |
monthOptions / yearOptions |
Entries { value, label, disabled } for dropdowns. |
select(iso), clear() |
Change the selection. |
focus(iso) |
Move the focused / visible date. |
goToMonth(n), nextMonth(), prevMonth() |
Navigate months. |
goToYear(year), goToMonthIndex(i) |
Jump to a year (calendar numbering) or a month of the visible year. |
setOpen(bool), toggle(), isOpen() |
Popup control. |
isDateDisabled(iso), hasInvalidValue() |
Checks against the current options. |
getDirection() |
Resolved 'ltr' / 'rtl'. |
subscribe(fn), update(options), destroy() |
Store helpers for vanilla use. |
In React and Vue, months, weekdays, value, valueText, monthOptions and yearOptions are provided directly (in Vue as computed refs).
Prop getters
Each returns a plain object of attributes and handlers — spread it in React, v-bind it in Vue, or apply it with spread() / h() from dayfold/dom.
| Getter | Put it on | Provides |
|---|---|---|
getRootProps() |
wrapper | dir, data-dayfold |
getLabelProps() |
<label> |
id, htmlFor → input |
getInputProps() |
<input> |
value, placeholder, aria-invalid, parse on blur / Enter, Alt+↓ opens |
getTriggerProps() |
<button> |
aria-haspopup, aria-expanded, aria-controls, dynamic aria-label |
getDialogProps() |
popup | role="dialog", aria-modal, aria-label, Esc, focus trap |
getPrevButtonProps() / getNextButtonProps() |
<button> |
aria-label, aria-disabled at min / max |
getMonthSelectProps() / getYearSelectProps() |
<select> |
aria-label, value, onChange |
getClearButtonProps() |
<button> |
aria-label, clears the value |
getMonthLabelProps(month) |
heading / caption | id that labels the grid |
getGridProps(month) |
<table> |
role="grid", aria-labelledby, aria-multiselectable |
getWeekdayProps(weekday) |
<th> |
role="columnheader", full weekday name |
getWeekProps() |
<tr> |
role="row" |
getCellProps(day) |
<td> |
role="gridcell", aria-selected, data-* state |
getDayProps(day) |
<button> |
roving tabIndex, aria-label, aria-current, aria-disabled, keyboard |
getLiveRegionProps() |
element | role="status" (with announce: 'manual') |
getHiddenInputProps({ name, part }) |
<input> |
type="hidden" ISO value for native forms |
getTimeProps(date?) |
<time> |
dateTime |
To add your own handler, call dayfold's too: onClick={(e) => { track(); dp.getDayProps(day).onClick(e) }}.
Calendar data
interface CalendarDay {
date: string // '2026-09-29'
day: number // day of month in the primary calendar
label: string // localised digits, e.g. '٢٩'
fullLabel: string // 'Tuesday, September 29, 2026'
secondaryLabel?: string // day in secondaryCalendar
secondaryFullLabel?: string
weekday: number // 0 = Sunday
isToday, isSelected, isDisabled, isOutside, isFocused, isWeekend: boolean
isRangeStart, isRangeEnd, isInRange, isInPreview: boolean
}
Guides
Disabling dates
import { today } from 'dayfold'
useDatePicker({
disabled: [
{ before: today() }, // all past dates
{ after: '2027-06-30' }, // everything after a date
{ from: '2026-12-24', to: '2026-12-26' }, // an inclusive range (either end optional)
{ before: '2026-01-01', after: '2026-12-31' }, // everything outside a window
'2026-11-11', // one date (string, Date or Temporal)
{ dayOfWeek: [5, 6] }, // weekdays (0 = Sunday) — here Fri & Sat
(iso) => holidays.has(iso), // any custom rule
],
})
Disabled dates stay focusable and are announced as "unavailable", so keyboard and screen-reader users can still explore; ranges can't span them. Use min / max when navigation should stop too.
Linked start & end fields
Options are re-read on every render, so one field can restrict another at runtime:
const [start, setStart] = useState<string | null>(null)
const [end, setEnd] = useState<string | null>(null)
<DateField label="Start date" value={start} onValueChange={setStart}
disabled={end ? { after: end } : undefined} />
<DateField label="End date" value={end} onValueChange={setEnd}
disabled={start ? { before: start } : undefined} />
- A picker opening without a value focuses the nearest selectable day — the end picker opens on the start date.
- If a value becomes disabled because the other field changed, its input gets
aria-invalid="true"andhasInvalidValue()returnstrue. - Vue:
useDatePicker(() => ({ disabled: start.value ? { before: start.value } : undefined })). Vanilla:endPicker.update({ ...options, disabled: { before: start } }).
Range and multiple selection
const range = useDatePicker({ mode: 'range', numberOfMonths: 2 })
// range.value → { start: '2026-10-01', end: '2026-10-05' }
const multi = useDatePicker({ mode: 'multiple', maxSelections: 5 })
// multi.value → ['2026-10-01', '2026-10-03']
Days expose isRangeStart, isRangeEnd, isInRange and isInPreview (the tentative range while choosing the end) plus matching data-* attributes.
Month & year dropdowns
<select {...dp.getMonthSelectProps()}>
{dp.monthOptions.map((m) => <option key={m.value} value={m.value} disabled={m.disabled}>{m.label}</option>)}
</select>
<select {...dp.getYearSelectProps()}>
{dp.yearOptions.map((y) => <option key={y.value} value={y.value} disabled={y.disabled}>{y.label}</option>)}
</select>
Options are localised and calendar-aware (Hijri years like 1448, 13 months in a Hebrew leap year). Keep the dropdowns mounted across month changes so they keep focus.
Text input & typed shortcuts
import { withShortcuts } from 'dayfold/shortcuts'
const dp = useDatePicker({ locale: 'en-GB', parse: withShortcuts() })
<label {...dp.getLabelProps()}>Departure</label>
<input {...dp.getInputProps()} />
<button {...dp.getTriggerProps()}>📅</button>
{dp.state.open && <div {...dp.getDialogProps()}>{/* calendar */}</div>}
The default parser follows the locale's numeric order (29/09/2026 in en-GB, 09/29/2026 in en-US) and accepts ISO dates and Arabic-Indic digits. withShortcuts() adds today, tomorrow, +3d, -2w, in 1 month, next fri, and Arabic اليوم, غدا, أمس, بعد 3 أيام.
dayfold manages the popup's open state, focus on open, Escape, the focus trap, outside clicks and returning focus to the trigger; positioning is yours (the native popover attribute or CSS anchor positioning work well).
Hijri and other calendars
// Hijri (Umm al-Qura) with Gregorian beneath each day — Arabic digits and RTL come from the locale
useDatePicker({ locale: 'ar-SA', calendar: 'islamic-umalqura', secondaryCalendar: 'gregory' })
// Gregorian with Hijri beneath, Latin digits
useDatePicker({ locale: 'en-SA', secondaryCalendar: 'islamic-umalqura', numberingSystem: 'latn' })
// Persian (Jalali)
useDatePicker({ locale: 'fa-IR', calendar: 'persian' })
Arabic accessible labels:
import { ar } from 'dayfold/locales/ar'
useDatePicker({ locale: 'ar-SA', labels: ar })
Styling
State is exposed as data attributes on both the cell and the day button:
[data-selected] { background: black; color: white; }
[data-today] { font-weight: 700; }
[data-outside] { color: gray; }
[data-disabled] { text-decoration: line-through; }
[data-in-range], [data-preview] { background: #eee; }
[data-range-start] { border-radius: 99px 0 0 99px; }
[data-range-end] { border-radius: 0 99px 99px 0; }
[aria-disabled='true'] { cursor: not-allowed; }
Tailwind: data-[selected]:bg-black data-[outside]:text-gray-400 aria-disabled:cursor-not-allowed.
Forms, SSR & SEO
- Native forms:
<input {...dp.getHiddenInputProps({ name: 'date' })} />posts the ISO value. Range mode sendsstart/end, or one input per end withpart: 'start' | 'end'. - Server rendering: no browser globals are touched at import or render. React and Vue use
useId()for hydration-safe ids. Passlocale(andtodayif needed) so server and client agree. Node and browsers can ship different ICU data, so addsuppressHydrationWarningto formatted month names or render the calendar client-only. - Machine-readable dates:
<time {...dp.getTimeProps()}>rendersdatetime="2026-09-29". - No layout shift:
fixedWeeks(default) keeps every month at six rows.
Accessibility
- W3C APG date-picker dialog and grid patterns, with a real
<button>in every cell. - One Tab stop for the grid (roving
tabindex); disabled dates remain focusable and are announced as unavailable. - Month and selection changes are announced in a polite live region.
- Popup:
role="dialog",aria-modal, focus moves in on open, Tab is trapped, Escape closes and returns focus to the trigger. - State is never colour-only — it is in the accessible name and in data attributes.
- Arrow keys follow reading direction in RTL.
- Verified with axe-core (WCAG 2.2 AA rules) in the test suite.
Labels
Every accessible string can be overridden per instance:
| Label | Default | Used for |
|---|---|---|
dialog |
"Choose date" | Popup name |
prevMonth / nextMonth |
"Previous month" / "Next month" | Navigation buttons |
monthSelect / yearSelect |
"Month" / "Year" | Dropdowns |
clear |
"Clear" | Clear button |
today, selected, unavailable, rangeStart, rangeEnd |
"Today", "selected", … | Words inside day labels |
trigger(valueText) |
"Choose date" / "Change date, Sep 29, 2026" | Trigger button name |
day(day, labels) |
"Today, Tuesday, September 29, 2026, selected" | Full day label |
monthChanged(label) |
the month label | Announcement after navigation |
selectionChanged(valueText) |
"Selected Sep 29, 2026" | Announcement after a selection |
useDatePicker({
labels: {
dialog: 'Choose your check-in date',
day: (d, l) => [d.fullLabel, d.isDisabled && 'fully booked'].filter(Boolean).join(', '),
},
})
You still own the rest of the page: give the input a visible label, keep text contrast at 4.5:1 and day buttons at least 24×24 px (44 px recommended).
Keyboard
| Key | Action |
|---|---|
| ← / → | Previous / next day (swapped in RTL) |
| ↑ / ↓ | Same weekday, previous / next week |
| Home / End | First / last day of the week |
| Page Up / Page Down | Previous / next month |
| Shift + Page Up / Page Down | Previous / next year |
| Enter / Space | Select the focused day |
| Esc | Close the popup and return focus |
| Tab / Shift + Tab | Move between popup controls (trapped when modal) |
| Alt + ↓ (in input) | Open the popup |
| Enter (in input) | Parse and commit the typed date |
Browser support
All evergreen browsers: Chrome / Edge 92+, Firefox 90+, Safari 15.4+ (iOS 15.4+). The optional field.css uses light-dark() for automatic dark mode where supported and falls back to the light theme elsewhere. Node 18+ for server rendering and tests.
Entry points & sizes
| Import | Contents | Size (min+gzip) |
|---|---|---|
dayfold |
createDatePicker() + date utilities |
7.5 kB |
dayfold/react |
useDatePicker() (includes core) |
7.7 kB |
dayfold/vue |
useDatePicker() (includes core) |
7.9 kB |
dayfold/react/field |
<DateField> (includes core) |
8.8 kB |
dayfold/field.css |
Optional styles for <DateField> |
1.6 kB |
dayfold/dom |
spread(), h() for vanilla JS |
0.3 kB |
dayfold/shortcuts |
Typed shortcuts parser | 1.8 kB |
dayfold/locales/ar |
Arabic accessible labels | < 0.5 kB |
Size budgets are enforced in CI — a change that grows a bundle past its budget fails the build.
FAQ
Does it include a time picker? Not yet — dayfold picks dates. Pair it with <input type="time"> or your own time control.
What value format do I get? ISO date strings ("2026-09-29"), never Date objects, so there are no time-zone shifts. Convert with toDate(iso) or Temporal.PlainDate.from(iso).
Does the Hijri calendar match the official Umm al-Qura calendar? It uses the browser's ICU islamic-umalqura data, which is based on the official Umm al-Qura tables.
Can I use it with Next.js / Nuxt? Yes — it is SSR-safe. See Forms, SSR & SEO.
Angular, Svelte, Solid? Use the framework-free core (createDatePicker + subscribe) — the prop getters are plain objects.
License
Related Packages
Vue 3 datepicker supporting Jalali, Hijri, Gregorian, Chinese calendars with ran...
A lightweight, zero-dependency Persian (Jalali / Shamsi) date and range picker f...
An accessible Vue 3 Persian (Jalali) calendar, date picker, and time picker with...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.1.0 | >=3.5.0 | MIT |