Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Livewire Calendar Laravel Package

omnia-digital/livewire-calendar

A Livewire component for displaying calendars in Laravel apps. Render events, navigate months, and customize day cells with minimal setup. Supports drag-and-drop, event listeners, and flexible slots for building interactive scheduling UIs without writing JavaScript.

View on GitHub
Deep Wiki
Context7

Getting Started

The 4.1.0 release is the "Livewire 4" line of omnia-digital/livewire-calendar, and the headline for day-to-day work is that nothing you already have should break: the package detects your installed Livewire version at runtime and adapts, so the same ^4.1 constraint works on Livewire 2, 3, or 4. That makes this a low-risk upgrade and a good moment to adopt if you'd been holding off on the 4.x line.

Minimal path:

composer require omnia-digital/livewire-calendar:^4.1
{{-- resources/views/dashboard.blade.php --}}
<livewire:calendar :events="$events" />
// app/Livewire/Dashboard.php
public function render()
{
    return view('livewire.dashboard', [
        'events' => Booking::query()
            ->whereBetween('starts_at', [$this->rangeStart, $this->rangeEnd])
            ->get()
            ->map(fn (Booking $b) => [
                'title'       => $b->title,
                'description' => $b->customer_name,
                'start'       => $b->starts_at->toDateString(),
                'end'         => $b->ends_at->toDateString(),
                'url'         => route('bookings.show', $b),
            ]),
    ]);
}

Where to look first, in this order:

  1. README compatibility matrix — new in this release. Confirm your exact PHP / Laravel / Livewire triple before anything else, especially if you're mid-upgrade on Livewire 4.
  2. README event/API reference for your pinned version — the emitted event names and prop signatures are the one area where the Livewire 2 → 4 abstraction may still surface version differences in your calling code.
  3. UPGRADE.md — new, and genuinely useful if you're coming from 3.2.0. It documents the migration path step-by-step rather than leaving you to infer it from the diff.
  4. CHANGELOG — now complete back to 2.1.0, which is the fastest way to check whether a behaviour you're relying on changed somewhere in 2.x → 4.x.

First use case to build: a read-only month view over an existing Eloquent model. Get the mapping layer right (model → plain event array) before touching clicks, drag-and-drop, or custom views.

Implementation Patterns

Map models to arrays in one place, not in the view. The component expects a plain collection of event-shaped items (title, start, end, plus optional description, url). Put that mapping in a dedicated presenter, transformer, or a toCalendarEvent() method on the model, and use it from every calendar you build. Passing Eloquent models straight through works until it doesn't — lazy-loaded relations get serialized into the Livewire payload, and you leak fields you didn't intend to expose.

Scope the query to the visible window. A calendar component that asks for "all events" is the classic production incident: fine in dev with 20 rows, fatal with 50,000. Use the component's month/range navigation event (the monthChange-style emit — check the README for your version's exact name) to update $rangeStart / $rangeEnd on your component, then re-query with a whereBetween. Always query on overlap, not containment:

->where('starts_at', '<=', $rangeEnd)
->where('ends_at', '>=', $rangeStart)

Otherwise multi-day events that begin before the window silently disappear.

Handle interaction with listeners, not by editing the package. For click-through and drag-to-reschedule, register listeners on your own component and persist there:

// Livewire 3/4 style
#[On('eventClick')]
public function openEvent(string $eventId): void
{
    $this->redirect(route('bookings.show', $eventId));
}

#[On('eventDrop')]
public function reschedule(string $eventId, string $newStart, string $newEnd): void
{
    Booking::findOrFail($eventId)->update([
        'starts_at' => $newStart,
        'ends_at'   => $newEnd,
    ]);
}

If you're still on Livewire 2 in part of the estate, the $listeners array form is the equivalent — the package's version detection won't rewrite your listener syntax for you. Keep both idioms out of the same file; branch per app, not per method.

Keep the calendar dumb, put policy in the query. Per-user, per-tenant, and permission-scoped calendars are just ->where('team_id', auth()->user()->current_team_id) in the event provider. Don't try to hide events client-side — they're in the Livewire payload either way.

Customise by publishing views, not by forking. If you need a different event chip, publish the package views and override the partial. That's the extension point that survives minor bumps; forking means re-merging on every release.

Test with Livewire::test() against your wrapper component, asserting the event collection is correctly shaped and correctly scoped — not against the package's internal rendering. You care that your query is right and your listeners persist correctly; the package's own markup is its problem.

If you maintain a package that depends on this one, mirror the compatibility matrix in your CI: Livewire 2 / 3 / 4 × PHP 7.4–8.4 × Laravel 9–12 is a real matrix now, and the release notes imply the maintainers are running it.

Gotchas and Tips

"No breaking changes" is not "no changes." A 3.2.0 → 4.1.0 jump skips a major number. The release notes claim full backward compatibility with Livewire 2 and 3, and the version-detection approach supports that — but Livewire 4's own upgrade has its own breaking changes (asset handling, component lifecycle, wire: directives). Upgrading this package is safe; upgrading Livewire because of this package is a separate project. Do them in separate PRs.

Clear caches after the bump. Version-detection packages commonly resolve behaviour from a cached compiled view or a published config/asset. After composer update, run php artisan view:clear && php artisan config:clear, and re-publish any assets you'd previously published (vendor:publish --force) so you're not running Livewire 4 against Livewire 3-era published markup.

Timezone drift is the #1 calendar bug. The package renders what you give it; it doesn't normalise. If your starts_at is stored UTC but your users think in Europe/London, events will land on the wrong day at month boundaries — and only at month boundaries, so it survives testing. Decide once: either convert to the display timezone in the mapper (->timezone(config('app.user_timezone'))->toDateString()) or store local. Don't do both.

All-day and multi-day events need end to be inclusive or exclusive — pick one and be consistent. Off-by-one on the last day is the second most common bug in this class of component.

PHP 7.4 support is a constraint on you, not just the package. Because 4.1.0 still supports 7.4, the package can't use PHP 8 features internally, and its method signatures stay 7.4-compatible. If you subclass or override package methods, keep your signatures compatible — adding a typed parameter or a return type that the parent lacks will fatal on some PHP versions.

Broad version constraints cut both ways. Supporting Laravel 6–12 means the dependency constraints are wide open, which makes composer why-not omnia-digital/livewire-calendar 4.1.0 your first debugging command when the install fails. It also means the lower end of that matrix (Laravel 6, PHP 7.4) is long past security support — a passing CI matrix there is not a security statement. Don't treat the matrix as permission to stay on EOL Laravel.

When the calendar renders empty, check three things in this order: (1) is $events a Collection, not a plain array or paginator; (2) does every item have both start and end, and is end >= start; (3) is the date format parseable. A single malformed item can take the whole month down rather than skipping quietly — ->filter() the collection in the mapper while debugging.

Debugging drag-and-drop: dd() in the listener before the DB write. If the listener never fires, the problem is the emitted event name for your Livewire version, not your persistence code — cross-check the README event list against the version you actually have installed.

N+1 hiding in the mapper. Accessing $booking->customer->name inside a map() over a month of events is a select * from customers where id in (...) per row. ->with('customer') on the calendar query, always.

Releasing to maintainers: the new RELEASING.md is worth a skim even if you only consume the package — it tells you how quickly a Livewire 4.x fix will land and what the maintainers expect in an issue report.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route