Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

webrobert's avatar

A pikaday date range component using two Livewire props

It’s not perfect yet but the dates are meant to reference each other and they do.

I would love some feedback (aside from the obvious moving from CDN files). It works but it feels a bit clunky to me. JavaScript (alpine, etc.) is not my strong suit. Here goes, no pride in authorship…

usage... (wire model any two date props)

<x-date-range-picker class="flex items-end">
     <x-slot name="start_date" wire:model="todo.start_date"></x-slot>
     <x-slot name="end_date"   wire:model="todo.due_date"></x-slot>
</x-date-range-picker>

date-range-picker.blade.php component

@props([ 'start_date', 'end_date' ])

@php( $sharedClasses = "border-0 border-b p-0 w-40 text-base" )

<div x-data="pikaDateRange($wire)" {{ $attributes }}>
    <input x-ref="start" type="text"  placeholder="Start date..."
           {{ $start_date->attributes->merge(['class' => $sharedClasses ]) }} />

    <span class="px-1">to</span>

    <input x-ref="end" type="text"   placeholder="End date..."
           {{ $end_date->attributes->merge(['class' => $sharedClasses ]) }} />
    
</div>

@pushOnce('head-css')
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/pikaday/css/pikaday.css">
@endPushOnce

@pushOnce('scripts')
<script src="https://cdn.jsdelivr.net/npm/pikaday/pikaday.js"></script>
<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('pikaDateRange', (wire) => ({
            init() {
                
                let wireModelEnd   = this.$refs.end.getAttribute('wire:model');
                let wireModelStart = this.$refs.start.getAttribute('wire:model');

                let end_date = new Pikaday({...{
                        field: this.$refs.end,
                        onSelect: function () {
                            wire.set( wireModelEnd, end_date.toString(), true)
                        },
                    }, ...PikadaySharedCollection()
                });

                let start_date = new Pikaday({...{
                        field: this.$refs.start,
                        onSelect: function () {
                            end_date.config({minDate: window.moment(this.getDate()).add(1, 'days').toDate()});
                            wire.set(wireModelStart, start_date.toString(), true)
                        },
                    }, ...PikadaySharedCollection()
                });

                start_date.config({ minDate: window.moment().toDate() });
            }
        }))
    })

    // array for items that share between Pikaday instances
    function PikadaySharedCollection() {
        return { toString(date) { return window.moment(date).format('ddd, MMM D, YYYY') } }
    }
</script>
@endPushOnce
0 likes
1 reply

Please or to participate in this conversation.