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ží.
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 datumDateTimePicker::make('birth_date')->asDate() // DateTime (výchozí)DateTimePicker::make('event_at')DateTimePicker::make('event_at')->asDateTime() // Jen časDateTimePicker::make('alarm')->asTime() // Jen měsíc + rok („YYYY-MM")DateTimePicker::make('period')->asMonth() // Explicitní setter režimuDateTimePicker::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áTimePickertutéž 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
timenebodatetimev každém dni, který kalendář dovolí. Pickerdatenebomonthhodiny 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 pickerutimeplatí 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ůTimePickerui nativní<select>slotů na okraji okna prostě končí. Server okno hlídá stejným pravidlemDateWithinBoundsjako data, s vlastní hláškou („Čas v poli … nesmí být dříve než 06:00“). - Dotykové kolečko pickeru
datetimeokno zatím nezašedí; hodnotu mimo něj ale server odmítne. - Formát.
H:ineboH:i:s('6:00'se přečte jako06: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()atimezone()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 udatetime: samotné datum nebo čas jsou wall-clock hodnoty, které by převod poškodil.
displayFormat()používá tokeny PHPdate()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žimdate_format,time_formatnebodatetime_formatzconfig/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
datetimejsou 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 naminutesStep()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. PickerasTime()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ýdenHome / End první / poslední den týdnePageUp / PageDown předchozí / další měsíc (se Shiftem rok)Enter / Space vybrat den s fokusem↑ ↓ na ciferníku předchozí / další hodina či minutaEscape 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:309.3.2026 14:309/3/2026 14:309. 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ředtypeable(): 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žetypeable(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()utimenebodatetime) nikdy nejde na<input type="time">: pro prohlížeč jestepvalidač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
stepv 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()domaxDate(). 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á nadnativeOnMobile();native()vyhrává nad ním. Řídí semobileBreakpoint()pole a výchozí hodnota pro celou aplikaci jewire-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.