⌘K

Formuláře

DateTimePicker

Jedno pole pro datum, měsíc, čas nebo obojí — režim rozhoduje o kalendáři, formátu i o tom, co se uloží.

DateTimePicker preview
Na této stránce

Jednotný date/time picker s režimy date, month, time a datetime.

use NyonCode\WireForms\Components\DateTimePicker;

Režimy

// Jen datum
DateTimePicker::make('birth_date')->asDate()
 
// DateTime (výchozí)
DateTimePicker::make('event_at')
DateTimePicker::make('event_at')->asDateTime()
 
// Jen čas
DateTimePicker::make('alarm')->asTime()
 
// Jen měsíc + rok („YYYY-MM")
DateTimePicker::make('period')->asMonth()
 
// Explicitní setter režimu
DateTimePicker::make('x')->mode('date') // 'date', 'month', 'time', 'datetime'

asMonth() vždy renderuje nativní <input type="month"> prohlížeče — vlastní kalendář nemá month-only mřížku — takže zůstane nativní i když předáte ->native(false).

asTime() vybírá čas na desktopu na ciferníku, na telefonu steppery. Pro pole, jehož časy jsou sloty — otevírací doba, termíny — ukládá TimePicker tutéž hodnotu, ale vybírá ji ze seznamu v pevném intervalu.

Omezení data

DateTimePicker::make('start')
->minDate('2024-01-01')
->maxDate('2025-12-31')
->disabledDates(['2024-12-25', '2024-12-31'])
->firstDayOfWeek(1) // pondělí
->closeOnDateSelection()

Meze přijmou cokoli, co jde přečíst jako datum — Carbon/DateTimeInterface, nebo řetězec jako '2026-07-10', '10.07.2026', 'today' či '+1 week' — a na pozadí se převedou do tvaru, kterému widget rozumí. Mez, kterou přečíst nelze, vyhodí výjimku, místo aby ji prohlížeč tiše zahodil.

DateTimePicker::make('start')
->minDate(now()) // žádná data v minulosti
->maxDate(now()->addYear())

U režimu datetime může mez nést i čas — ten pak omezí hodiny jen v ten hraniční den:

DateTimePicker::make('slot')
->minDate('2026-07-10 08:30') // 10. července nejdřív od 08:30
->maxDate('2026-07-20 17:00') // 20. července nejpozději do 17:00

Horní mez zadaná na celý den pokrývá celý den: ->maxDate('2026-07-20') nechá 20. července volitelné až do 23:59.

Meze a zakázané dny jsou zároveň validační pravidla. Picker je jen kreslí a kresbu jde obejít — hodnotou napsanou do pole nebo kolečkem data telefonu, které na iOS nabízí každý den bez ohledu na min a max. Pole si proto přidá vlastní pravidlo (Validation\Rules\DateWithinBounds), kdykoli má co hlídat, a chybová hláška pojmenuje mez v displayFormat(), pokud je nastavený. Pole bez mezí a bez zakázaných dnů žádné pravidlo nepřidá.

Denní časové okno

minDate() a maxDate() omezují dny; čas, který nesou, platí jen první či poslední den. Otevírací doba je jiné pravidlo — denní doba, která platí každý den — a tu nastavují minTime() / maxTime():

DateTimePicker::make('appointment_at')
->minDate('2026-10-01')
->maxDate('2026-12-31')
->minTime('06:00') // každý den od 06:00…
->maxTime('18:00') // …do 18:00
->minutesStep(15)

Jak se vyhodnotí:

  • Každý den. Okno platí pro hodiny pickeru time nebo datetime v každém dni, který kalendář dovolí. Picker date nebo month hodiny nemá, takže se tam obě metody ignorují.
  • Vyhrává přísnější. V hraniční den, jehož minDate()/maxDate() nese čas, platí pozdější z obou dolních mezí (a dřívější z horních). U pickeru time platí vždy obě, protože má jen jeden den.
DateTimePicker::make('slot')
->minDate('2026-10-01 08:30') // 1. října až od 08:30, ne od 06:00
->minTime('06:00')
->maxTime('18:00')
  • Nakreslené, pak ohlídané. V panelu je hodina či minuta mimo okno zašedlá, hodina, která do okna zasahuje jen zčásti, zůstane volitelná a čas se do okna vtáhne (výběr 18 při maxTime('18:00') dá 18:00) a prázdné hodiny se otevřou na začátku okna, ne o půlnoci. Seznam slotů TimePickeru i nativní <select> slotů na okraji okna prostě končí. Server okno hlídá stejným pravidlem DateWithinBounds jako data, s vlastní hláškou („Čas v poli … nesmí být dříve než 06:00“).
  • Dotykové kolečko pickeru datetime okno zatím nezašedí; hodnotu mimo něj ale server odmítne.
  • Formát. H:i nebo H:i:s ('6:00' se přečte jako 06:00), DateTimeInterface (vezme se jeho čas) nebo Closure s $get. Cokoli jiného — '6 pm', '25:00' — vyhodí výjimku při vykreslení pole, místo aby tiše zakázalo všechny hodiny, nebo žádnou.

Volby času

DateTimePicker::make('meeting')
->withSeconds()
->hoursStep(1)
->minutesStep(15)
->secondsStep(30)

Formát

DateTimePicker::make('date')
->format('Y-m-d') // formát uložení
->displayFormat('d.m.Y') // formát zobrazení
->timezone('Europe/Prague')

format() a timezone() jsou opt-in a uplatní se při uložení. Bez nich se hodnota uloží přesně tak, jak ji vyrobil widget — přidání na existující field je tedy vědomá změna toho, co skončí ve sloupci, nikdy tichá. timezone() převádí oběma směry a jen u datetime: samotné datum nebo čas jsou wall-clock hodnoty, které by převod poškodil.

displayFormat() používá tokeny PHP date() a mění jen to, co vidí uživatel — uložená hodnota zůstává beze změny. Ctí ho vlastní picker; formát zobrazení nativního inputu patří prohlížeči a locale uživatele. Když není nastavený, platí pro daný režim date_format, time_format nebo datetime_format z config/wire-forms.php — kromě pole se sekundami, jehož nastavený formát sekundy nemá; to ukazuje hodnotu tak, jak je uložená.

Desktopový panel

Od mobilního breakpointu pole výš je panel stavěný pro myš a klávesnici; pod ním si telefon nechává své ovládání — bottom sheet se steppery, nativní vstup nebo dotykové kolečko — beze změny. Obojí kreslí tentýž controller nad týmž stavem, takže hodnota vybraná v jednom je hodnota, kterou ukáže druhé.

  • Hlavička listuje šipkami po měsících a název měsíce i rok jsou tlačítka: měsíc otevře mřížku dvanácti měsíců, rok mřížku dvaceti let. Datum o pět let zpět je rok → měsíc → den, ne šedesát kliknutí. Měsíce a roky celé mimo minDate()/maxDate() jsou zašedlé a šipky se na mezích zastaví.
  • Hodiny pickeru datetime jsou vedle kalendáře jako ciferník, který kreslí TimePicker — ciferník hodin (venku 1–12, uvnitř 13–23 a 00), pak minut, s přichycením na minutesStep() a se zašedlými hodinami a minutami mimo meze. Tady nastavuje hodnotu průběžně, bez vlastního OK: panel zavře jeho Hotovo. Picker asTime() ukáže jen ciferník.
  • Dnes / Teď v patičce vybere dnešní den (a s hodinami aktuální čas zaokrouhlený dolů na krok), pokud ho meze nevylučují. Hotovo zavře panel datetime; Vymazat pole vyprázdní.
  • Klávesnice. ↓ v poli nebo ikona kalendáře otevře panel s fokusem na vybraném dni (jinak na dnešku vtaženém do mezí); kliknutí do pole ho otevře a kurzor nechá v poli pro psaní.
← → předchozí / další den
↑ ↓ předchozí / další týden
Home / End první / poslední den týdne
PageUp / PageDown předchozí / další měsíc (se Shiftem rok)
Enter / Space vybrat den s fokusem
↑ ↓ na ciferníku předchozí / další hodina či minuta
Escape zavřít a vrátit se do pole

Den, který meze nebo disabledDates() vylučují, se přeskočí ve směru pohybu, nikdy se na něm nepřistane.

Psaní z klávesnice

Trigger je textové pole, ne tlačítko: hodnotu lze napsat, nejen vybrat. Napsaný text se čte zpět stejným formátem, jakým se zobrazuje — displayFormat(), když je nastavený, jinak tvar uložené hodnoty — takže pole ukazující 9. 3. 2026 14:30 přesně tohle zpátky přijme.

Parser je benevolentní ke všemu kromě pořadí částí, které určuje formát. Při ->displayFormat('j. n. Y H:i') skončí všechny tyhle zápisy na stejné hodnotě:

9. 3. 2026 14:30
9.3.2026 14:30
9/3/2026 14:30
9. 3. 26 14:30 dvojciferný rok patří do tohoto století
9. 3. 2026 čas se nenapsal, zůstává ten, který je právě nastavený

Zápis se potvrdí při opuštění pole a klávesou Enter; Escape ho zahodí. Cokoli, co parser nepřečte — 31. 2. 2026, hodina nad 23, den, který vylučuje minDate()/maxDate()/disabledDates() — je odmítnuto celé a vrátí se předchozí hodnota, takže se do stavu nikdy nedostane rozečtené datum. Vyprázdnění pole hodnotu smaže.

Napsaná hodnota projde stejným ořezem jako vybraná: v hraniční den, který nese čas, se hodiny stáhnou do meze místo odmítnutí — napsat 10. 3. 2026 07:00 při ->minDate('2026-03-10 08:30') uloží 08:30.

Cestu přes klávesnici zavřete tam, kde hodnota opravdu musí přijít z widgetu:

DateTimePicker::make('slot')->typeable(false)

readOnly() má přednost před typeable(): zavírá klávesnici i panel, protože hodnota není uživatelova, aby ji měnil jakoukoli cestou. typeable(false) zavírá jen klávesnici a kalendář nechává funkční.

Psaní je vlastnost vlastního pickeru. Klávesnice nativního inputu patří prohlížeči a jediný způsob, jak ji vzít, je readonly — což by s ní vyplo i vlastní picker prohlížeče — takže typeable(false) pod ->native() nemá žádný efekt.

Nativní picker

Výchozí je vlastní Alpine picker. Přepnutí na ovládání prohlížeče:

DateTimePicker::make('date')
->native() // použít nativní picker prohlížeče
->native(false) // zpět na vlastní picker (výchozí)

Jedinou výjimkou je asMonth(), který je vždy nativní.

Nativní vstup času nebo data a času nese step odvozený z nejjemnější jednotky, kterou jste nastavili — secondsStep() (nebo 1 s withSeconds()), jinak minutesStep(), jinak hoursStep(). Teprve díky tomu nativní vstup vůbec ukáže sekundy (výchozí krok prohlížeče je minuta), a na tento krok pak hodnotu drží i validace prohlížeče. displayFormat() a typeable() patří vlastnímu pickeru; nativní vstup formátuje a píše se tak, jak určí locale prohlížeče.

Nativní jen na telefonu

Kalendář se s myší ovládá pohodlně a na telefonu je stísněný, přičemž prohlížeč už má kolečko data, které uživatel zná. nativeOnMobile() ponechá vlastní picker od mobilního breakpointu pole výš a pod ním vykreslí vstup prohlížeče:

DateTimePicker::make('starts_at')
->minDate('today')
->minutesStep(15)
->nativeOnMobile() // telefon: nativní datetime-local; desktop: kalendář

V markupu jsou oba, navázané na stejný stav, a CSS na breakpointu ukáže jeden — v prohlížeči se nic nerozhoduje, takže nic neprobliká. Nativní dvojče dostane vlastní id ({id}-native) a samo se pojmenuje; required() se na obou polovinách změní na aria-required, protože povinný vstup, který styly skryjí, by na druhé velikosti obrazovky zablokoval formulář. Bottom sheet kalendáře se nevykreslí, tu obrazovku vlastní nativní vstup.

native() nad ním vyhrává. Na telefonu je nativní každý picker — vlastní se tam ovládá hůř — a co prvek telefonu sám neumí, se dohání jinak:

  • Krok hodin (minutesStep(), hoursStep() u time nebo datetime) nikdy nejde na <input type="time">: pro prohlížeč je step validační pravidlo, ne kolečko, a iOS nabízí každou minutu. Čas s krokem je nativní <select> slotů; datum a čas s krokem je nativní vstup data vedle tohoto selectu, složené v prohlížeči do jednoho stavu (samotné datum nic nezapíše).
  • Zakázané dny a meze kolečko telefonu nezašedí (iOS ignoruje i min/max), takže je odmítne server — viz omezení data.
  • Sekundy — nativní vstup času nese step v sekundách, který Android ukáže; kolečko iOS sekundy nemá a uloží :00.

Výchozí hodnota pro celou aplikaci je wire-core.mobile.native; explicitní native(false) z ní pole vyřadí.

Dotykové kolečko na telefonu

Telefon může místo desktopového panelu i prvku prohlížeče dostat dotykové kolečko: sloupce v bottom sheetu, které dojíždějí a zacvakávají jako vlastní picker telefonu — hodiny a minuty u času, den / měsíc / rok u data a sloupec dnů vedle hodin u data s časem (tvar z iOS: „Po 21. 9. · 14 : 30“).

TimePicker::make('opens_at')
->minDate('08:00')->maxDate('18:00')
->touchOnMobile() // telefon: kolečko; desktop: picker
  • Každý sloupec je obyčejný scroller s CSS scroll-snap, takže setrvačnost a zacvaknutí jsou fyzika samotné platformy. Řádky se natáčejí jako válec a na Androidu otočení krátce zavibruje (na iOS web haptiku nemá).
  • Sloupce hodin vznikají ze slotů pole (interval i meze uplatněné); roky u data a dny u data s časem sahají od minDate() do maxDate(). Kombinace, kterou by pole odmítlo, je zašedlá a nikdy nezůstane: za mezí kolečka skočí přesně na mez, 31. únor vrátí den na 28., zakázaný den se posune na sousední a čas mimo slot otočí druhý sloupec.
  • Během otáčení se nic nezapisuje: Hotovo uloží, Zrušit, pozadí i tažení úchytu dolů hodnotu ponechají; Vymazat pole vyprázdní. Prázdné pole se otevře na nejbližším slotu od teď.
  • Každý sloupec je pro čtečky a klávesnici spinbutton (šipky, Home/End); sheet drží fokus a po dobu otevření zamyká scroll stránky.
  • Měsíce a dny v týdnu jsou pojmenované podle jazyka stránky (<html lang>).
  • Pro všechny režimy kromě asMonth(). Vyhrává nad nativeOnMobile(); native() vyhrává nad ním. Řídí se mobileBreakpoint() pole a výchozí hodnota pro celou aplikaci je wire-core.mobile.touch — stejný přepínač, který selectům dává dotykový seznam.

Metody

Metoda Typ Popis
mode(string) string Nastavit režim: date, month, time, datetime
asDate() — Alias pro mode('date')
asTime() — Alias pro mode('time')
asMonth() — Alias pro mode('month'); vždy nativní
asDateTime() — Alias pro mode('datetime')
format(string) string Formát uložení (Carbon kompatibilní)
displayFormat(string) string Formát zobrazení ukázaný uživateli; výchozí z wire-forms.date_format / time_format / datetime_format
minDate(string|DateTimeInterface|Closure) string Nejdřívější volitelné datum; u datetime může nést i čas
maxDate(string|DateTimeInterface|Closure) string Nejpozdější volitelné datum; mez na celý den pokrývá celý den
disabledDates(array|Closure) array Data, která nelze vybrat
firstDayOfWeek(int) int 0=neděle, 1=pondělí
closeOnDateSelection() bool Zavřít picker po výběru data
withSeconds() bool Zobrazit sloupec sekund v time pickeru
hoursStep(int) int Krok inkrementu hodin
minutesStep(int) int Krok inkrementu minut
secondsStep(int) int Krok inkrementu sekund
minTime(string|Closure|null) string Nejdřívější denní čas platný každý den, H:i/H:i:s; jen time/datetime — viz denní časové okno
maxTime(string|Closure|null) string Nejpozdější denní čas platný každý den
touchOnMobile(bool $condition = true) bool Dotykové kolečko v bottom sheetu pod mobilním breakpointem; ne pro asMonth() (výchozí: false) — viz dotykové kolečko na telefonu
timezone(string) string Zobrazí hodnotu v této timezone a při uložení ji převede zpět do timezone aplikace; jen pro datetime
native(bool $native = true) bool Použít nativní ovládání prohlížeče místo vlastního pickeru (výchozí: false)
nativeOnMobile(bool $condition = true) bool Nativní ovládání prohlížeče jen pod mobilním breakpointem, nad ním vlastní picker (výchozí: wire-core.mobile.native, false); krok hodin vykreslí nativní datum + <select> slotů
typeable(bool|Closure) bool Umožnit hodnotu napsat, nejen vybrat (výchozí: true); jen vlastní picker
disabled(bool|Closure) bool Znepřístupnit picker
readOnly(bool|Closure) bool Read-only režim — bez psaní i bez panelu
required() — Označit jako povinné
live() — Spustit Livewire update při změně

Popisek, hint, tooltip a další sdílené metody viz Společné API pole.