Introduction
The DatePicker component is a zero dependencies, fully accessible, and deeply customizable that wraps the powerful Calendar component with an elegant dialog, preset buttons, and intelligent date formatting. It combines the full feature set of the calendar (single, multiple, and range selection modes) with a polished UI layer that includes preset ranges, smart formatting...
it differ from the calendar of dialog-based date selector with presets, formatting, and positioning. Perfect for triggering from buttons or input fields.
Installation
Use the sheaf artisan command to install the date-picker component:
php artisan sheaf:install date-picker
Then import the script in your JS entry point:
// app.js import './components/date-picker/index.js';
import the css (if you haven't did it for the calendar component before):
/* app.css */ @import './components/calendar/cell.css';
Once installed, you can use the
<x-ui.date-picker />component in any Blade view.
if you're using range mode with livewire, we recomend to register the synthesizer in your service provider so Livewire knows how to serialize the DateRange object between requests:
use App\Livewire\Synthesizers\DateRangeSynthesizer; use Livewire\Livewire; // ... public function boot(): void { Livewire::propertySynthesizer(DateRangeSynthesizer::class); }
Usage
Bind to Livewire
Use wire:model to sync the calendar with a Livewire property. The format depends on the mode.
Single Mode
public ?string $date = null;
<x-ui.date-picker mode="single" wire:model="date" />
Multiple Mode
public array $dates = [];
<x-ui.date-picker mode="multiple" wire:model="dates" />
Range Mode
A) Simple associative array (start + end as ISO strings):
public array $range = ['start' => null, 'end' => null];
<x-ui.date-picker mode="range" wire:model="range" />
B) DateRange object (recommended – provides presets, date methods, and seamless hydration).
See The DateRange Synth for full details.
use App\View\Components\DateRange; public DateRange $range; // .... public function mount(){ $this->range = new DateRange(start: now(), end: now()->addDays(2)); }
<x-ui.date-picker mode="range" wire:model="range" />
Using with Alpine
Outside Livewire, bind with x-model:
<!-- Single --> <div x-data="{ date: null }"> <x-ui.date-picker x-model="date" /> </div> <!-- bind durrent's day date --> <div x-data="{ date: new Date().toISOString() }"> <x-ui.date-picker x-model="date" /> </div> <!-- Multiple --> <div x-data="{ dates: [] }"> <x-ui.date-picker mode="multiple" x-model="dates" /> </div> <!-- Range (simple object) --> <div x-data="{ range: { start: null, end: null } }"> <x-ui.date-picker mode="range" x-model="range" /> </div>
Trigger
The date picker supports two trigger types: a default button and bindable text inputs for direct keyboard entry.
Button (default)
The default trigger is a styled button that displays the selected date and opens the calendar on click.
Range Separator
Change the separator between start and end date in range display:
<x-ui.date-picker mode="range" range-separator="→" />
Input
Bind a masked text input directly to the date picker for keyboard-first date entry. Inputs are context-aware arrow keys increment/decrement each segment, typing auto-advances between segments, and the calendar stays in sync all built from absolute scratch (see calendar/masker.js file).
Supported in
singleandrangemodes only.
Single Mode
Pass <x-ui.date-picker.input /> into the trigger slot:
<x-ui.date-picker> <x-slot:trigger> <x-ui.date-picker.input /> </x-slot> </x-ui.date-picker>
Range Mode
In range mode, use the dedicated start and end input components. Each input is independently editable and stays in sync with the calendar selection.
<x-ui.date-picker mode="range" :months="2"> <x-slot:trigger class="flex gap-2"> <x-ui.field> <x-ui.label>Start</x-ui.label> <x-ui.date-picker.input.start /> </x-ui.field> <x-ui.field> <x-ui.label>End</x-ui.label> <x-ui.date-picker.input.end /> </x-ui.field> </x-slot> </x-ui.date-picker>
Pillbox variant
you can use the pills only in multiple mode
Min & Max Dates
Restrict the selectable date range by setting min and max. Dates outside this range are disabled and cannot be selected.
<x-ui.date-picker min="2026-04-05" max="2026-04-25" wire:model="date" />
Unavailable Dates
Mark specific dates as unavailable (visible but disabled) using a comma-separated array of ISO date strings.
<x-ui.date-picker :unavailable-dates="$blockedDates" wire:model="date" />
Range Constraints
In range mode, enforce minimum and maximum range lengths with min-range and max-range (both in days).
{{-- Require at least 3 days, at most 2 weeks --}} <x-ui.date-picker mode="range" :min-range="3" :max-range="14" wire:model="range" />
Display Multiple Months
Show multiple months side-by-side for easier date browsing.
{{-- Show 2 months side-by-side --}} <x-ui.date-picker :months="2" mode="range" wire:model="range" /> {{-- Show 3 months --}} <x-ui.date-picker :months="3" wire:model="date" />
Open To Date
Set the initial month the date picker opens to using open-to.
{{-- Open to September 2028 when no date is selected --}} <x-ui.date-picker open-to="2028-09-01" wire:model="date" /> {{-- Always open to this date, even if a date is already selected --}} <x-ui.date-picker open-to="2028-09-01" force-open-to wire:model="date" />
Navigation Controls
Disable month navigation buttons if needed.
<x-ui.date-picker :allow-navigation="false" />
Selectable Months & Years
Enable dropdown selectors for quick jumps to specific months and years.
<x-ui.date-picker selectable-months selectable-years wire:model="date" />
Years Range Configuration
The years-range prop accepts an array with two values [start, end]:
- Relative offsets: Values with absolute value ≤ 100 are treated as offsets from the current year. For example,
[-10, 10]shows years from 10 years ago to 10 years in the future. - Absolute years: Larger values (e.g.,
2020) are treated as absolute year numbers. For example,[2020, 2030]shows years 2020 through 2030.
When multiple months are displayed, the month and year selectors appear only in the first month's header to avoid duplication.
Size Variants
Choose from multiple sizes to fit different UI contexts.
<x-ui.date-picker size="xs" /> <x-ui.date-picker size="sm" /> <x-ui.date-picker size="md" /> {{-- default --}} <x-ui.date-picker size="lg" /> <x-ui.date-picker size="xl" /> <x-ui.date-picker size="2xl" />
Today Button
Show a button to jump to today's date.
<x-ui.date-picker :with-today="true" wire:model="date" />
Week Numbers
Display ISO 8601 week numbers for project planning and reporting.
<x-ui.date-picker week-numbers wire:model="date" />
Fixed Week Heights
Lock all months to a consistent layout height (6 rows) for stable layouts.
<x-ui.date-picker :fixed-weeks="true" :months="2" wire:model="date" />
Readonly
Display the date picker without allowing interaction.
<x-ui.date-picker readonly />
Localization
Set Locale
Override the browser's default locale to control weekday names and the first day of the week.
<x-ui.date-picker locale="fr-Ma" wire:model="date" /> <!-- backend driven --> <x-ui.date-picker :locale="app()->getLocale()" wire:model="date" />
Custom Week Start
Override the locale-determined first day of the week.
{{-- Force Monday as first day regardless of locale --}} <x-ui.date-picker locale="en-US" :start-day="1" wire:model="date" />
Special Days
Mark specific dates with custom categories for styling, disabling, and tooltips. This is especially useful for booking systems where you need to highlight holidays, unavailable dates, or special events.
Mark Special Dates with Color
Pass a special-days associative array where each key is a category name.
<div class=" [&_[data-special~=holiday]]:text-yellow-600 [&_[data-special~=birthday]]:text-pink-500 [&_[data-special~=blocked]]:text-red-500 "> <x-ui.date-picker :special-days="[ 'holiday' => ['2026-04-20', '2026-04-21'], 'birthday' => ['2026-04-15'], 'blocked' => ['2026-04-25', '2026-04-27'], ]" /> </div>
Disable Specific Categories
Prevent selection of certain special day categories.
<x-ui.date-picker :special-days="[ 'holiday' => ['2026-04-20', '2026-04-21'], 'blocked' => ['2026-04-25'], ]" :special-disabled="['blocked']" />
Now dates with the blocked category cannot be selected, while holidays remain selectable.
Add Tooltips
Show helpful text on hover for special day categories.
<x-ui.date-picker :special-days="[...]" :special-disabled="['blocked']" :special-tooltips="[ 'blocked' => 'Blocked day – unavailable', 'holiday' => 'Public holiday', 'birthday' => 'Birthday celebration 🎂', ]" />
Special Days Scenario
Use special days for a booking system where customers can see available, booked, and featured dates:
@php your php $bookedDates = app(BookingRepository::class)->getBookedDates(); $featuredDates = app(PropertyRepository::class)->getFeaturedDates(); // Today onwards to 1 year from now $minDate = now()->format('Y-m-d'); $maxDate = now()->addYear()->format('Y-m-d'); @endphp <div class="[&_[data-special~=booked]]:line-through [&_[data-special~=booked]]:opacity-50 [&_[data-special~=featured]]:font-bold [&_[data-special~=featured]]:text-amber-600"> <x-ui.date-picker mode="range" :min-range="2" :max-range="14" :min="$minDate" :max="$maxDate" :special-days="[ 'booked' => $bookedDates, 'featured' => $featuredDates, ]" :special-disabled="['booked']" :special-tooltips="[ 'booked' => 'Already reserved', 'featured' => 'Special rate available!', ]" wire:model="stay" /> </div>
Date Picker In Form
use other form component like label and field... to build forms in pair with date-picker...
<x-ui.field> <x-ui.label>Pick a date</x-ui.label> <x-ui.date-picker wire:model="multiple" clearable /> </x-ui.field>
The DateRange Synthesizer
When using mode="range" with Livewire, we recommend binding the calendar to a DateRange object instead of a raw ['start'=>'...', 'end'=>'...']. This powerful object extends Laravel's CarbonPeriod and provides a rich API for working with date ranges.
Installation
First, register the synthesizer in your service provider:
use App\Livewire\Synthesizers\DateRangeSynthesizer; use Livewire\Livewire; // ... public function boot(): void { Livewire::propertySynthesizer(DateRangeSynthesizer::class); }
Basic Usage
In your Livewire component, type-hint the property:
use App\View\Components\DateRange; class Dashboard extends Component { public DateRange $range; public function mount() { // Initialize as empty range $this->range = new DateRange(); // Or initialize with specific dates $this->range = new DateRange('2026-04-15', '2026-04-25'); // Or using Carbon instances $this->range = new DateRange(now()->subDays(1), now()->addDays(4)); } }
Then bind it to your calendar view:
<x-ui.calendar mode="range" wire:model.live="range" />
Presets
Date picker includes powerful preset buttons for quick selection of common date ranges. Presets are context-aware and generate the appropriate date range based on today's date.
Pass a comma-separated string or array to show only specific presets:
{{-- Array style --}} <x-ui.date-picker mode="range" :presets="['today', 'this_week', 'this_month', 'last_month']" /> {{-- String style (comma-separated) --}} <x-ui.date-picker mode="range" presets="today,this_week,this_month,last_month" />
Core Methods
// Get the start date as a Y-m-d string (or null if not set) $start = $this->vacation->getStart(); // e.g., "2026-04-15" // Get the end date as a Y-m-d string (or null if not set) $end = $this->vacation->getEnd(); // e.g., "2026-04-25" // Check if the range has a start date if ($this->vacation->hasStart()) { // Start is set } // Check if the range has an end date if ($this->vacation->hasEnd()) { // End is set } // Get the preset used to create this range (e.g., DateRangePreset::ThisWeek) $preset = $this->vacation->getPreset(); // Manually set the preset (e.g., after modifying dates) $this->vacation->preset(DateRangePreset::Custom); // Create a new range with only a start date $partial = DateRange::setStart('2026-04-15'); // end will be null
Advanced Use Cases
Because DateRange extends CarbonPeriod, you can leverage its full power.
Iterating Over the Range
foreach ($this->range as $date) { echo $date->format('Y-m-d'); // Each $date is a Carbon instance }
Filtering the Range
Use addFilter() to include or exclude specific days. For example, to get all weekdays within a range:
$weekdays = $this->range->addFilter('isWeekday')->toArray();
Using with Eloquent
The DateRange object works directly with whereBetween:
use App\Models\Booking; $bookings = Booking::whereBetween('date', $this->range)->get();
Validating the Range
use Illuminate\Validation\Validator; public function rules(): array { return [ 'vacation.start' => 'required|date_format:Y-m-d', 'vacation.end' => 'required|date_format:Y-m-d|after:vacation.start', ]; }
Panel Position
Control where the date picker dialog appears relative to the trigger button using the position and offset props.
{{-- Bottom-left (default) --}} <x-ui.date-picker position="bottom-start" offset="3" /> {{-- Bottom-right --}} <x-ui.date-picker position="bottom-end" offset="3" /> {{-- Top-left --}} <x-ui.date-picker position="top-start" offset="3" /> {{-- Top-right --}} <x-ui.date-picker position="top-end" offset="3" />
Available positions: top-start, top, top-end, bottom-start, bottom, bottom-end, left-start, left, left-end, right-start, right, right-end.
Component Props
x-ui.date-picker
| Prop | Type | Default | Description |
|---|---|---|---|
trigger |
slot | null |
Custom trigger element. If not provided, a default button is shown. |
label |
string | 'select a date' |
Label text for the default trigger button. |
position |
string | 'bottom-start' |
Dialog position relative to trigger. Options: top-start, top, top-end, bottom-start, bottom, bottom-end, left-start, left, left-end, right-start, right, right-end. |
offset |
integer | 3 |
Distance in pixels between dialog and trigger. |
presets |
array|string | [] |
Preset keys to display. Pass as array or comma-separated string. Leave empty to hide presets. |
separator |
string | '→' |
Separator text between start and end date in range display. |
wire:model |
string | — | Binds to a Livewire property. Value format depends on mode. |
mode |
string | 'single' |
Selection mode. Options: single, multiple, range. |
min |
string | null |
Earliest selectable date as YYYY-MM-DD. |
max |
string | null |
Latest selectable date as YYYY-MM-DD. |
min-range |
integer | null |
Minimum range length in days (range mode only). |
max-range |
integer | null |
Maximum range length in days (range mode only). |
unavailable-dates |
array|string | [] |
Array or comma-separated list of unavailable dates as YYYY-MM-DD. |
special-days |
array | [] |
Associative array of category keys → arrays of ISO date strings. |
special-disabled |
array | [] |
List of category keys that should be non‑selectable (disabled). |
special-tooltips |
array | [] |
Associative array of category keys → tooltip text. |
locale |
string | 'auto' |
BCP‑47 locale for weekday names and first day of week. auto uses navigator.language. |
start-day |
integer|string | 'auto' |
First day of the week (0 = Sunday, 1 = Monday, …, 6 = Saturday). auto respects locale. |
months |
integer | 1 |
Number of months to display side‑by‑side. |
fixed-weeks |
boolean | false |
Lock all months to 6 rows for consistent layout height. |
allow-navigation |
boolean | true |
Show previous/next month navigation buttons. |
with-today |
boolean | false |
Show a "go to today" button. |
selectable-months |
boolean | false |
Show month selector dropdown. |
selectable-years |
boolean | false |
Show year selector dropdown. |
years-range |
array | [-10, 10] |
Range of selectable years. Values ≤ 100 are relative offsets from current year. |
readonly |
boolean | false |
Disable all interaction (display‑only). |
size |
string | 'md' |
Size variant. Options: xs, sm, md, lg, xl, 2xl. |
open-to |
string | null |
Date (YYYY-MM-DD) the calendar opens to when no date is selected. |
force-open-to |
boolean | false |
When true, forces calendar to always open to open-to, even if a date is selected. |
week-numbers |
boolean | false |
Show ISO week numbers in a separate column. |
top-inputs |
boolean | false |
Show date input field(s) above the calendar for direct keyboard entry. Note: typically handled by presets and formatting in date picker. |
x-ui.date-picker.input
x-ui.date-picker.input.start
x-ui.date-picker.input.end
Data Attributes
The date picker dialog and underlying calendar both expose data attributes for advanced CSS customization:
| Attribute | Description |
|---|---|
data-slot="calendar-cell" |
Applied to each selectable day <button>. |
data-slot="calendar-blank-day-cell" |
Applied to blank days from adjacent months. |
data-selected |
Present on a cell when its date is selected. |
data-disabled |
Present on a cell when its date is disabled (outside min/max or unavailable). |
data-unavailable |
Present on a cell when explicitly marked unavailable (still visible, non-selectable). |
data-today |
Present on a cell representing today's date. |
data-focused |
Present on the currently focused cell (keyboard navigation). |
data-range-middle |
Present on cells between the start and end of a selected range. |
data-hover-preview |
Present on cells in the range preview while selecting range end (before click). |
data-hover-end |
Present on the hovered cell while selecting range end. |
data-first-in-row |
Present on the first cell of each week row. |
data-last-in-row |
Present on the last cell of each week row. |
data-special |
Present on cells that have at least one special category. Value is a space‑separated list of category keys (e.g., "holiday birthday"). |
data-has-tooltip |
Present on cells that have a tooltip (from special-tooltips). Useful for CSS selectors like [data-has-tooltip]:hover [data-special-tooltip]. |
data-slot="calendar-week-num-cell" |
Applied to each week number cell. |