mirror of
https://github.com/tabler/tabler.git
synced 2026-10-12 05:06:55 +04:00
Add dateFormat patterns and boundInput to Datepicker
This commit is contained in:
1 parent
4f31a3bcc4
commit
1b4ae2c330
5 files changed
+249
-23
No files matched your search
@@ -0,0 +1,6 @@
|
||||
---
|
||||
"@tabler/core": minor
|
||||
"@tabler/docs": patch
|
||||
---
|
||||
|
||||
Added `dateFormat` patterns such as `iso` or `DD.MM.YYYY` and a `boundInput` option for ISO form values to `Datepicker`.
|
||||
+111
-17
@@ -39,6 +39,8 @@ const SELECTOR_BOUND_INPUT = 'input[type="hidden"], input[name]'
|
||||
const HIDE_DELAY = 100 // ms delay before hiding after selection
|
||||
|
||||
const DATE_PATTERN = /^(\d{4})-(\d{2})-(\d{2})$/
|
||||
const FORMAT_TOKENS = /YYYY|MM|M|DD|D/g
|
||||
const ISO_FORMAT = 'YYYY-MM-DD'
|
||||
|
||||
// Vanilla Calendar Pro 3.4 moved several months, the time picker, week
|
||||
// numbers, popups and animation into extensions that must be registered when
|
||||
@@ -84,8 +86,13 @@ type ComponentConfig = {
|
||||
datepickerTheme: string | null
|
||||
dateMin: DateAny | null
|
||||
dateMax: DateAny | null
|
||||
/** `Intl.DateTimeFormat` options, or a function(date, locale) returning the text shown in the field */
|
||||
dateFormat: Intl.DateTimeFormatOptions | ((date: Date, locale: string | undefined) => string) | null
|
||||
/** input that receives the picked dates as `YYYY-MM-DD`, comma-separated; an inline calendar finds a hidden one inside */
|
||||
boundInput: string | HTMLInputElement | null
|
||||
/**
|
||||
* How the date is written into the field: a pattern such as `'DD.MM.YYYY'` (tokens `YYYY`, `MM`, `M`, `DD`, `D`),
|
||||
* `'iso'`, `Intl.DateTimeFormat` options, or a function(date, locale) returning the text
|
||||
*/
|
||||
dateFormat: string | Intl.DateTimeFormatOptions | ((date: Date, locale: string | undefined) => string) | null
|
||||
/** element that shows the formatted date; a button uses itself or its `[data-bs-datepicker-display]` child */
|
||||
displayElement: string | HTMLElement | boolean | null
|
||||
displayMonthsCount: MonthsCount
|
||||
@@ -111,6 +118,7 @@ type ComponentConfigInput = Partial<ComponentConfig> & Record<string, unknown>
|
||||
type ChangeEventArgs = { dates: string[]; event: MouseEvent }
|
||||
|
||||
const Default: ComponentConfig = {
|
||||
boundInput: null,
|
||||
datepickerTheme: null,
|
||||
dateMin: null,
|
||||
dateMax: null,
|
||||
@@ -129,10 +137,11 @@ const Default: ComponentConfig = {
|
||||
}
|
||||
|
||||
const DefaultType: Record<keyof ComponentConfig, string> = {
|
||||
boundInput: '(null|string|element)',
|
||||
datepickerTheme: '(null|string)',
|
||||
dateMin: '(null|string|number|object|date)',
|
||||
dateMax: '(null|string|number|object|date)',
|
||||
dateFormat: '(null|object|function)',
|
||||
dateFormat: '(null|string|object|function)',
|
||||
displayElement: '(null|string|element|boolean)',
|
||||
displayMonthsCount: 'number',
|
||||
firstWeekday: 'number',
|
||||
@@ -146,6 +155,43 @@ const DefaultType: Record<keyof ComponentConfig, string> = {
|
||||
vcpOptions: 'object',
|
||||
}
|
||||
|
||||
const pad = (value: number, length = 2): string => String(value).padStart(length, '0')
|
||||
|
||||
const formatPattern = (date: Date, pattern: string): string => {
|
||||
const parts: Record<string, string> = {
|
||||
YYYY: pad(date.getFullYear(), 4),
|
||||
MM: pad(date.getMonth() + 1),
|
||||
M: String(date.getMonth() + 1),
|
||||
DD: pad(date.getDate()),
|
||||
D: String(date.getDate()),
|
||||
}
|
||||
|
||||
return pattern.replace(FORMAT_TOKENS, (token) => parts[token]!)
|
||||
}
|
||||
|
||||
// Reads text written with `pattern` back into `YYYY-MM-DD`, or null when it
|
||||
// does not match or names a day that does not exist.
|
||||
const parsePattern = (value: string, pattern: string): string | null => {
|
||||
const order: string[] = []
|
||||
const source = pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(FORMAT_TOKENS, (token) => {
|
||||
order.push(token[0]!)
|
||||
return token === 'YYYY' ? '(\\d{4})' : token.length === 2 ? '(\\d{2})' : '(\\d{1,2})'
|
||||
})
|
||||
const match = new RegExp(`^${source}$`).exec(value)
|
||||
if (!match) {
|
||||
return null
|
||||
}
|
||||
|
||||
const parts: Record<string, number> = { Y: 0, M: 1, D: 1 }
|
||||
order.forEach((key, index) => {
|
||||
parts[key] = Number(match[index + 1])
|
||||
})
|
||||
|
||||
const { Y: year = 0, M: month = 1, D: day = 1 } = parts
|
||||
const date = new Date(year, month - 1, day)
|
||||
return date.getMonth() === month - 1 && date.getDate() === day ? `${pad(year, 4)}-${pad(month)}-${pad(day)}` : null
|
||||
}
|
||||
|
||||
// Delegated Data API handlers run in the capture phase, before the plugin's
|
||||
// own click listener, which opens the popup from a `setTimeout`. Two nested
|
||||
// timeouts are the first point that is after it for certain.
|
||||
@@ -180,6 +226,7 @@ class Datepicker extends BaseComponent {
|
||||
_isInput = false
|
||||
_isInline = false
|
||||
_boundInput: HTMLInputElement | null = null
|
||||
_boundInputInside = false
|
||||
_positionElement: HTMLElement | null = null
|
||||
_displayElement: HTMLElement | false | null = null
|
||||
_themeObserver: MutationObserver | null = null
|
||||
@@ -304,7 +351,7 @@ class Datepicker extends BaseComponent {
|
||||
if (clone && clone !== this._element && clone.isConnected) {
|
||||
if (this._isInput) {
|
||||
clone.replaceWith(this._element)
|
||||
} else if (this._boundInput) {
|
||||
} else if (this._boundInput && this._boundInputInside) {
|
||||
const copy = SelectorEngine.findOne(SELECTOR_BOUND_INPUT, clone)
|
||||
if (copy) {
|
||||
copy.replaceWith(this._boundInput)
|
||||
@@ -324,8 +371,7 @@ class Datepicker extends BaseComponent {
|
||||
}
|
||||
|
||||
setSelectedDates(dates: DatesArr): void {
|
||||
this._selectedDates = dates.map((date) => this._toIsoDate(date))
|
||||
this._calendar?.set({ selectedDates: this._selectedDates, ...this._monthOf(this._selectedDates[0]) })
|
||||
this._select(dates.map((date) => this._toIsoDate(date)))
|
||||
this._writeSelection(this._selectedDates)
|
||||
}
|
||||
|
||||
@@ -334,10 +380,8 @@ class Datepicker extends BaseComponent {
|
||||
this._isInput = this._element.tagName === 'INPUT'
|
||||
this._isInline = this._config.inline
|
||||
|
||||
// For inline mode, look for a hidden input child to bind to
|
||||
if (this._isInline && !this._isInput) {
|
||||
this._boundInput = SelectorEngine.findOne(SELECTOR_BOUND_INPUT, this._element) as HTMLInputElement | null
|
||||
}
|
||||
this._boundInput = this._resolveBoundInput()
|
||||
this._boundInputInside = Boolean(this._boundInput && this._element.contains(this._boundInput))
|
||||
|
||||
this._positionElement = this._resolvePositionElement()
|
||||
this._displayElement = this._resolveDisplayElement()
|
||||
@@ -366,6 +410,13 @@ class Datepicker extends BaseComponent {
|
||||
this._parseInputValue()
|
||||
}
|
||||
|
||||
// The field shows localized text the next page load cannot read back, so
|
||||
// a value the server rendered into the bound input selects the dates.
|
||||
const boundDates = this._boundInput?.value.split(',').filter((date) => DATE_PATTERN.test(date))
|
||||
if (this._selectedDates.length === 0 && boundDates?.length) {
|
||||
this._select(boundDates)
|
||||
}
|
||||
|
||||
// Populate input/display with preselected dates
|
||||
this._updateDisplayWithSelectedDates()
|
||||
}
|
||||
@@ -395,6 +446,17 @@ class Datepicker extends BaseComponent {
|
||||
}
|
||||
}
|
||||
|
||||
_resolveBoundInput(): HTMLInputElement | null {
|
||||
const { boundInput } = this._config
|
||||
|
||||
if (boundInput) {
|
||||
return getElement(boundInput) as HTMLInputElement | null
|
||||
}
|
||||
|
||||
// An inline calendar submits through a hidden input inside it
|
||||
return this._isInline && !this._isInput ? (SelectorEngine.findOne(SELECTOR_BOUND_INPUT, this._element) as HTMLInputElement | null) : null
|
||||
}
|
||||
|
||||
_resolvePositionElement(): HTMLElement {
|
||||
let { positionElement } = this._config
|
||||
|
||||
@@ -679,6 +741,11 @@ class Datepicker extends BaseComponent {
|
||||
const locale = this._config.locale === 'default' ? undefined : this._config.locale
|
||||
const { dateFormat } = this._config
|
||||
|
||||
// Token pattern, independent of the locale
|
||||
if (typeof dateFormat === 'string') {
|
||||
return formatPattern(date, this._formatPattern()!)
|
||||
}
|
||||
|
||||
// Custom function formatter
|
||||
if (typeof dateFormat === 'function') {
|
||||
return dateFormat(date, locale)
|
||||
@@ -693,6 +760,20 @@ class Datepicker extends BaseComponent {
|
||||
return date.toLocaleDateString(locale)
|
||||
}
|
||||
|
||||
_formatPattern(): string | null {
|
||||
const { dateFormat } = this._config
|
||||
|
||||
if (typeof dateFormat !== 'string') {
|
||||
return null
|
||||
}
|
||||
|
||||
return dateFormat.toLowerCase() === 'iso' ? ISO_FORMAT : dateFormat
|
||||
}
|
||||
|
||||
_dateSeparator(): string {
|
||||
return this._config.selectionMode === 'multiple-ranged' ? ' – ' : ', '
|
||||
}
|
||||
|
||||
_formatDateForInput(dates: string[]): string {
|
||||
if (dates.length === 0) {
|
||||
return ''
|
||||
@@ -703,8 +784,7 @@ class Datepicker extends BaseComponent {
|
||||
}
|
||||
|
||||
// For date ranges, use en-dash; for multiple dates, use comma
|
||||
const separator = this._config.selectionMode === 'multiple-ranged' ? ' – ' : ', '
|
||||
return dates.map((date) => this._formatDate(date)).join(separator)
|
||||
return dates.map((date) => this._formatDate(date)).join(this._dateSeparator())
|
||||
}
|
||||
|
||||
_parseInputValue(): void {
|
||||
@@ -715,11 +795,21 @@ class Datepicker extends BaseComponent {
|
||||
|
||||
const written = writtenSelections.get(this._element)
|
||||
if (written && written.text.trim() === value) {
|
||||
this._selectedDates = [...written.dates]
|
||||
this._calendar?.set({ selectedDates: this._selectedDates, ...this._monthOf(this._selectedDates[0]) })
|
||||
this._select(written.dates)
|
||||
return
|
||||
}
|
||||
|
||||
// A pattern reads back what it wrote, e.g. a value the server sent again
|
||||
const pattern = this._formatPattern()
|
||||
if (pattern) {
|
||||
const parts = this._config.selectionMode === 'single' ? [value] : value.split(this._dateSeparator())
|
||||
const dates = parts.map((part) => parsePattern(part.trim(), pattern))
|
||||
if (dates.every(Boolean)) {
|
||||
this._select(dates as string[])
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// `YYYY-MM-DD` is read as a local date: `new Date('2020-06-20')` would be
|
||||
// UTC midnight and land on the previous day west of Greenwich.
|
||||
const date = DATE_PATTERN.test(value) ? this._parseDate(value) : new Date(value)
|
||||
@@ -727,8 +817,12 @@ class Datepicker extends BaseComponent {
|
||||
return
|
||||
}
|
||||
|
||||
this._selectedDates = [this._toIsoDate(date)]
|
||||
// The calendar opens on the month of the value, not on today.
|
||||
this._select([this._toIsoDate(date)])
|
||||
}
|
||||
|
||||
_select(dates: string[]): void {
|
||||
this._selectedDates = [...dates]
|
||||
// The calendar opens on the month of the selection, not on today.
|
||||
this._calendar?.set({ selectedDates: this._selectedDates, ...this._monthOf(this._selectedDates[0]) })
|
||||
}
|
||||
|
||||
@@ -788,7 +882,7 @@ EventHandler.on(document, EVENT_FOCUSIN_DATA_API, SELECTOR_DATA_TOGGLE, function
|
||||
initAll(SELECTOR_DATA_TOGGLE, Datepicker, (element) => {
|
||||
const { dataset } = element
|
||||
|
||||
return dataset.bsInline === 'true' || dataset.tblrInline === 'true' || 'bsSelectedDates' in dataset || 'tblrSelectedDates' in dataset || Boolean((element as HTMLInputElement).value)
|
||||
return dataset.bsInline === 'true' || dataset.tblrInline === 'true' || 'bsSelectedDates' in dataset || 'tblrSelectedDates' in dataset || 'bsBoundInput' in dataset || 'tblrBoundInput' in dataset || Boolean((element as HTMLInputElement).value)
|
||||
})
|
||||
// js-docs-end datepicker-init
|
||||
|
||||
|
||||
@@ -502,4 +502,99 @@ describe('Datepicker', () => {
|
||||
expect(input().value).toBe('not a date')
|
||||
})
|
||||
})
|
||||
|
||||
describe('format pattern and bound input', () => {
|
||||
it('writes an ISO value with the iso keyword whatever the locale', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" data-bs-locale="pl-PL" data-bs-date-format="iso" value="2026-09-30">'
|
||||
|
||||
const instance = new Datepicker(input())
|
||||
|
||||
expect(instance._config.dateFormat).toBe('iso')
|
||||
expect(input().value).toBe('2026-09-30')
|
||||
expect(instance._config.locale).toBe('pl-PL')
|
||||
})
|
||||
|
||||
it('writes a token pattern from a data attribute', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" data-bs-date-format="D/M/YYYY">'
|
||||
|
||||
const instance = new Datepicker(input())
|
||||
instance.setSelectedDates(['2026-03-04'])
|
||||
|
||||
expect(input().value).toBe('4/3/2026')
|
||||
})
|
||||
|
||||
it('joins a range written with a pattern', () => {
|
||||
fixtureEl.innerHTML = '<input type="text">'
|
||||
|
||||
const instance = new Datepicker(input(), { dateFormat: 'DD.MM.YYYY', selectionMode: 'multiple-ranged' })
|
||||
instance.setSelectedDates(['2026-06-10', '2026-06-18'])
|
||||
|
||||
expect(input().value).toBe('10.06.2026 – 18.06.2026')
|
||||
})
|
||||
|
||||
it('reads a value written with the pattern back', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" value="30.09.2026">'
|
||||
|
||||
const instance = new Datepicker(input(), { dateFormat: 'DD.MM.YYYY' })
|
||||
|
||||
expect(instance.getSelectedDates()).toEqual(['2026-09-30'])
|
||||
expect(input().value).toBe('30.09.2026')
|
||||
})
|
||||
|
||||
it('reads a range written with the pattern back', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" value="10.06.2026 – 18.06.2026">'
|
||||
|
||||
const instance = new Datepicker(input(), { dateFormat: 'DD.MM.YYYY', selectionMode: 'multiple-ranged' })
|
||||
|
||||
expect(instance.getSelectedDates()).toEqual(['2026-06-10', '2026-06-18'])
|
||||
})
|
||||
|
||||
it('does not read a day that does not exist', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" value="31.02.2026">'
|
||||
|
||||
const instance = new Datepicker(input(), { dateFormat: 'DD.MM.YYYY' })
|
||||
|
||||
expect(instance.getSelectedDates()).toEqual([])
|
||||
expect(input().value).toBe('31.02.2026')
|
||||
})
|
||||
|
||||
it('still reads an ISO value with another pattern', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" value="2026-09-30">'
|
||||
|
||||
const instance = new Datepicker(input(), { dateFormat: 'DD.MM.YYYY' })
|
||||
|
||||
expect(instance.getSelectedDates()).toEqual(['2026-09-30'])
|
||||
expect(input().value).toBe('30.09.2026')
|
||||
})
|
||||
|
||||
it('writes ISO dates into a bound input next to a popup field', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" data-bs-locale="pl-PL" data-bs-bound-input="#due"><input type="hidden" id="due" name="due">'
|
||||
const hidden = fixtureEl.querySelector<HTMLInputElement>('#due')!
|
||||
|
||||
const instance = new Datepicker(input())
|
||||
instance.setSelectedDates(['2026-09-30'])
|
||||
|
||||
expect(input().value).toBe('30.09.2026')
|
||||
expect(hidden.value).toBe('2026-09-30')
|
||||
})
|
||||
|
||||
it('selects the dates of a bound input the server filled in', () => {
|
||||
fixtureEl.innerHTML = '<input type="text" data-bs-locale="pl-PL" data-bs-bound-input="#due"><input type="hidden" id="due" name="due" value="2026-09-30">'
|
||||
|
||||
const instance = new Datepicker(input())
|
||||
|
||||
expect(instance.getSelectedDates()).toEqual(['2026-09-30'])
|
||||
expect(input().value).toBe('30.09.2026')
|
||||
})
|
||||
|
||||
it('leaves a bound input outside the element in place on dispose', () => {
|
||||
fixtureEl.innerHTML = '<button type="button" data-bs-bound-input="#due">Pick</button><input type="hidden" id="due" name="due">'
|
||||
const hidden = fixtureEl.querySelector<HTMLInputElement>('#due')!
|
||||
|
||||
new Datepicker(fixtureEl.querySelector('button')!).dispose()
|
||||
|
||||
expect(hidden.parentElement).toBe(fixtureEl)
|
||||
expect(fixtureEl.querySelector('button')!.contains(hidden)).toBe(false)
|
||||
})
|
||||
})
|
||||
})
|
||||
+2
-2
@@ -212,7 +212,7 @@
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.js",
|
||||
"maxSize": "58 kB"
|
||||
"maxSize": "59 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.min.js",
|
||||
@@ -220,7 +220,7 @@
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.esm.js",
|
||||
"maxSize": "58 kB"
|
||||
"maxSize": "59 kB"
|
||||
},
|
||||
{
|
||||
"path": "./dist/js/tabler.esm.min.js",
|
||||
|
||||
@@ -149,6 +149,25 @@ The popup lines up with the left edge of the field. Set `data-bs-placement` to `
|
||||
<input type="text" class="form-control" id="datepicker-right" data-bs-toggle="datepicker" autocomplete="off" data-bs-placement="right" placeholder="Select a date" />
|
||||
</Example>
|
||||
|
||||
### Date format
|
||||
|
||||
The field shows the date in the format of `data-bs-locale`. Set `data-bs-date-format` to a pattern to write it the same way in every language. The pattern uses `YYYY` for the year, `MM` and `M` for the month, and `DD` and `D` for the day. The short tokens drop the leading zero. Everything else is copied as it is. Use `iso` as a shortcut for `YYYY-MM-DD`.
|
||||
|
||||
<Example>
|
||||
<div class="row g-3">
|
||||
<div class="col-sm-6">
|
||||
<label class="form-label" for="datepicker-format-iso">ISO date, Polish calendar</label>
|
||||
<input type="text" class="form-control" id="datepicker-format-iso" data-bs-toggle="datepicker" autocomplete="off" data-bs-locale="pl-PL" data-bs-date-format="iso" value="2026-09-30" />
|
||||
</div>
|
||||
<div class="col-sm-6">
|
||||
<label class="form-label" for="datepicker-format-pattern">Custom pattern</label>
|
||||
<input type="text" class="form-control" id="datepicker-format-pattern" data-bs-toggle="datepicker" autocomplete="off" data-bs-date-format="DD/MM/YYYY" placeholder="DD/MM/YYYY" />
|
||||
</div>
|
||||
</div>
|
||||
</Example>
|
||||
|
||||
A field with a pattern also reads its `value` in that pattern, so a form the server sends back keeps the picked date selected.
|
||||
|
||||
### Button trigger
|
||||
|
||||
Any element can open the calendar, not only an input. A button shows the picked date as its text. Put the text in a child with `data-bs-datepicker-display` so an icon next to it stays.
|
||||
@@ -197,11 +216,22 @@ To submit the picked dates with a form, put a hidden input inside the calendar.
|
||||
</form>
|
||||
</Example>
|
||||
|
||||
A popup field works the same way. Point `data-bs-bound-input` at a hidden input and give the `name` to that input, not to the field. The field shows the date in the visitor's language, and the form sends `YYYY-MM-DD`. When the hidden input already has a value, the picker selects that date on page load.
|
||||
|
||||
<Example>
|
||||
<form onsubmit="return false">
|
||||
<label class="form-label" for="datepicker-bound">Due date</label>
|
||||
<input type="text" class="form-control" id="datepicker-bound" data-bs-toggle="datepicker" autocomplete="off" data-bs-locale="pl-PL" data-bs-bound-input="#datepicker-bound-value" placeholder="Select a date" />
|
||||
<input type="hidden" id="datepicker-bound-value" name="due_date" value="2026-09-30" />
|
||||
<button type="submit" class="btn btn-primary mt-3">Submit</button>
|
||||
</form>
|
||||
</Example>
|
||||
|
||||
## JavaScript
|
||||
|
||||
### Via data attributes
|
||||
|
||||
Add `data-bs-toggle="datepicker"` and Tabler does the rest. Inputs open on focus, other elements open on click, and inline calendars and fields with a value or `data-bs-selected-dates` render on page load. Every option below can be set as a `data-bs-*` attribute, for example `data-bs-selection-mode="multiple"`.
|
||||
Add `data-bs-toggle="datepicker"` and Tabler does the rest. Inputs open on focus, other elements open on click, and inline calendars and fields with a value, `data-bs-selected-dates` or `data-bs-bound-input` render on page load. Every option below can be set as a `data-bs-*` attribute, for example `data-bs-selection-mode="multiple"`.
|
||||
|
||||
<CodeDocs name="datepicker-init" file="core/js/src/datepicker.ts" />
|
||||
|
||||
@@ -223,12 +253,13 @@ const datepicker = new tabler.Datepicker(document.getElementById('my-date'), {
|
||||
| --- | --- | --- | --- |
|
||||
| `dateMin` | string, number, Date | `null` | First pickable date, as `YYYY-MM-DD`. |
|
||||
| `dateMax` | string, number, Date | `null` | Last pickable date, as `YYYY-MM-DD`. |
|
||||
| `dateFormat` | object, function | `null` | How the date is shown in the field. Pass `Intl.DateTimeFormat` options or a `function(date, locale)` that returns a string. |
|
||||
| `boundInput` | string, element | `null` | Input that gets the picked dates as `YYYY-MM-DD`, separated by commas. An inline calendar uses a hidden input inside it. |
|
||||
| `dateFormat` | string, object, function | `null` | How the date is shown in the field. Pass a pattern such as `'DD.MM.YYYY'`, `'iso'`, `Intl.DateTimeFormat` options or a `function(date, locale)` that returns a string. |
|
||||
| `displayElement` | string, element, boolean | `null` | Element that shows the picked date. A button uses itself or its `[data-bs-datepicker-display]` child. Set `false` to show nothing. |
|
||||
| `displayMonthsCount` | number | `1` | Months shown side by side. |
|
||||
| `firstWeekday` | number | `1` | First day of the week: 0 is Sunday, 1 is Monday. |
|
||||
| `inline` | boolean | `false` | Render the calendar in place instead of a popup. |
|
||||
| `locale` | string | `'default'` | Locale for month names and the date shown in the field, for example `'en-US'` or `'de-DE'`. |
|
||||
| `locale` | string | `'default'` | Locale for month names and the date shown in the field, for example `'en-US'` or `'de-DE'`. A `dateFormat` pattern takes over the field. |
|
||||
| `positionElement` | string, element | `null` | Element the popup lines up with. Defaults to the `.input-icon` or `.input-group` wrapper, or the field itself. |
|
||||
| `selectedDates` | array | `[]` | Preselected dates as `YYYY-MM-DD`. |
|
||||
| `selectionMode` | string | `'single'` | `'single'`, `'multiple'` or `'multiple-ranged'`. |
|
||||
@@ -298,5 +329,5 @@ Tabler 1.5 and older used [Litepicker](https://github.com/wakirin/Litepicker), w
|
||||
| `singleMode: false` | `data-bs-selection-mode="multiple-ranged"` |
|
||||
| `minDate` / `maxDate` | `data-bs-date-min` / `data-bs-date-max` |
|
||||
| `numberOfMonths: 2` | `data-bs-display-months-count="2"` |
|
||||
| `format` | `dateFormat` option, as `Intl.DateTimeFormat` options |
|
||||
| `format: 'DD.MM.YYYY'` | `data-bs-date-format="DD.MM.YYYY"` (tokens `YYYY`, `MM`, `M`, `DD`, `D`) |
|
||||
| `picker.on('selected', …)` | `change.bs.datepicker` event |
|
||||
Reference in new issue
Block a user