Open source October 2026
Wirepicker

Wirepicker

Wirepicker

Wirepicker is a date and date-range picker for Laravel that works with or without Livewire and with or without Alpine. It ships one Blade component, a small vanilla JS controller and its own CSS, with zero runtime dependencies, and shares the data-wire-theme attribute with wiremodal and wiretoast.

It exists because <input type="date"> shows the browser's format, not the page's: a Spanish page on an English browser reads mm/dd/yyyy, and the control cannot be styled.

Installation

composer require edulazaro/wirepicker
php artisan vendor:publish --tag=wirepicker-assets

The publish command drops CSS and JS into public/vendor/wirepicker:

<link rel="stylesheet" href="{{ asset('vendor/wirepicker/css/wirepicker.css') }}">
<script src="{{ asset('vendor/wirepicker/js/wirepicker.js') }}" defer></script>

With Vite you can skip publishing and import straight from vendor:

/* resources/css/app.css */
@import "../../vendor/edulazaro/wirepicker/resources/css/wirepicker.css";
// resources/js/app.js
import '../../vendor/edulazaro/wirepicker/resources/js/wirepicker.js';

wirepicker-lang and wirepicker-views publish the translations and the Blade view.

One date, or a range

<x-wirepicker wire:model="startsOn" />

The property holds a Y-m-d string, '' when empty. Any wire:model modifier works.

<x-wirepicker range wire:model.live="period" />
public array $period = ['start' => '', 'end' => ''];

The first click sets the start and the second the end, in either order, and the days in between light up under the pointer while the end is still open. A range can carry shortcuts beside the calendar:

<x-wirepicker range wire:model.live="period" :presets="['this-month', 'next-month', 'this-year']" />

The shortcuts are today, this-week, next-7-days, this-month, next-month, last-month and this-year. An unknown name is dropped.

Without Livewire

Give it a name and it posts like any field; a range posts period[start] and period[end]:

<x-wirepicker name="starts_on" value="2026-10-08" />
<x-wirepicker range name="period" :value="['start' => '2026-10-01', 'end' => '2026-10-31']" />

Every change also fires a bubbling wirepicker:change event on the root, which is all Alpine needs:

<div x-data="{ date: null }" x-on:wirepicker:change="date = $event.detail.value">
    <x-wirepicker />
</div>

Options

Prop Default
range false Two dates instead of one
presets [] Shortcuts beside the calendar, range only
placeholder translated Text while empty
min, max none First and last day that can be picked
clearable true A button to empty it
name, value none For a plain form
size md sm for toolbars
locale app locale Months, weekdays, format and first day of the week
week-start from the locale 0 Sunday to 6 Saturday
id none Set on the button, for <label for>

Every language, almost no translations

Months, weekdays, the date format and the first day of the week come from the browser's Intl, so es reads 08/10/2026 and starts on Monday while en-US reads 10/08/2026 and starts on Sunday, with no locale files. Only the package's own few words (the placeholder, Today, Clear and the shortcuts) are translated, in English and Spanish.

How it survives Livewire

The value lives in hidden fields inside the component, and the controller writes them and fires input and change: that is the whole contract with wire:model, a form and Alpine. Two details make it hold up after every Livewire request:

  • The fields are <input type="text" hidden>, not type="hidden". On a hidden input the value is the attribute, and a morph whose HTML carries no value empties it.
  • The calendar is drawn once on <body>, so no scrolling table, card or modal around the picker can clip it, and it opens above wiremodal's modals.

Theming

Pick the theme once on <html>, shared with the rest of the family:

<html data-wire-theme="studio">

The picker has the same eleven themes as the rest of the wire* family, with dark mode through data-wire-theme-mode="dark" or a .dark ancestor. A theme set on a container instead of <html> works too: the calendar takes the picker's theme with it when it opens.

For anything else, override CSS variables: the shared --wire-* ones for the whole family, or the picker's own --wp-* ones for the field and the calendar.

built and maintained by Edu Lazaro · MIT license