github saade/filament-fullcalendar v5.0.0

4 hours ago

Filament FullCalendar v5 is here

A month view of the calendar in Filament's theme

After a long time of incremental improvements, fixes, feature requests, and more than a few things I wanted to rethink, Filament FullCalendar v5 is ready.

This is much more than a compatibility release.

The goal with v5 was to make FullCalendar feel less like something embedded inside Filament and much more like something that actually belongs there.

The calendar now runs on FullCalendar 7, follows Filament's design language, uses Filament's actions and schemas more deeply, understands your models better, and gives you considerably more control without having to reach for custom JavaScript or Livewire workarounds.

In short: the calendar is now a much better Filament citizen.

Thank you to everyone who tested the betas and reported what broke. 💛

It finally feels like Filament

One of the biggest changes in v5 is something you'll notice immediately.

v5 moves to FullCalendar 7, and ships with a theme made for Filament. It takes its colors from your panel: the primary color for buttons, today and events, and the gray scale for borders and text. It follows your panel into dark mode, and its classes are Tailwind classes, compiled by your panel's theme. No more
CSS overrides fighting FullCalendar's stylesheet.

Toolbars use Filament buttons. Events look like Filament badges. Headers, dropdowns, list views and the +more popover all received the same treatment.

The result is a calendar that feels much less like a third-party component dropped into your panel.

And the integration goes beyond styling.

You can now give the widget a heading, description and header actions just like other Filament components, while the calendar toolbar itself can be composed from navigation buttons, views, filters, Filament actions and your own custom tools.

Pick a look

Prefer FullCalendar's own look? FullCalendar 7 comes with five themes, and v5 ships all of them, each with its color palettes:

FilamentFullCalendarPlugin::make()
    ->theme('monarch')
    ->palette('purple')
    ->nativeToolbar()
The filament theme
filament
The breezy theme
breezy
The classic theme
classic
The forma theme
forma
The monarch theme
monarch
The pulse theme
pulse

nativeToolbar() lets FullCalendar draw the toolbar in the theme's style instead of using Filament buttons. Your actions, filters and custom tools come along, with their icons, tooltips and badges.

Or make your own

None of those quite right? Write a FullCalendar 7 theme as a JavaScript module and register it with the plugin:

use Illuminate\Support\Facades\Vite;

FilamentFullCalendarPlugin::make()
    ->registerTheme('brutalist', fn (): string => Vite::asset('resources/js/calendar/brutalist.js'))
    ->theme('brutalist')

A theme can extends a built-in theme or another registered one, so you only write the parts you want to change. See Using a theme of your own for how to write and build one.

Colors work like Filament colors

color() takes the name of any color registered in Filament, such as success, or a palette from Filament's Color class for anything else:

use Filament\Support\Colors\Color;

EventData::make()->color('success');
EventData::make()->color(Color::hex('#fde047'))->contrastColor('#000');

The same goes for color() on event sources and eventColor() on resources. contrastColor() sets the text color on the themes that fill events with their color.

Filters and tabs are now first-class features

This has been one of the most requested areas of the plugin.

In v5, calendars can finally use Filament-style filters and tabs.

Filters are built using familiar Filament form fields and can appear in a dropdown, modal, slide-over, above the calendar or below it.

Tabs work much like resource list tabs, including badges and query modification.

Both can also remember their state between visits.

So things like:

  • filtering appointments by employee
  • switching between confirmed and pending bookings
  • showing events for a specific department
  • filtering resources, categories or locations

can now be part of the calendar itself instead of something you have to build around it.

Your models can be calendar events

Another major change in v5 is a much tighter relationship between your application models and the calendar.

Models can now describe how they should appear on a calendar themselves.

That means a calendar can work directly with your models instead of forcing every project to repeatedly transform them into event arrays.

Even better, one calendar can contain events backed by different models.

The plugin keeps track of which record each event represents and uses the appropriate model, policy, label and actions when the event is opened.

And one record can show up as several events, such as a rental with a pickup and a return:

class Rental extends Model implements Eventables
{
    public function toCalendarEvents(FetchInfo $info): array
    {
        return [
            EventData::make()->title("Pickup: {$this->car}")->start($this->pickup_at),
            EventData::make()->title("Return: {$this->car}")->start($this->return_at),
        ];
    }
}

Forms and infolists can also come directly from your Filament resources when you don't need something calendar-specific.

The end result is considerably less duplication between your resources and your calendar.

Actions are just Filament actions

Creating, viewing, editing and deleting events now uses Filament's own action system.

That means the same concepts you already use throughout a Filament application also apply to the calendar.

Custom actions can live alongside the defaults, authorization works through model policies, and actions automatically receive the relevant record.

After an action changes something, the calendar refreshes itself.

It sounds simple, but it removes a surprising amount of special handling that used to exist around calendar interactions.

Dragging events can actually update your records

Drag-and-drop has also been significantly improved.

Tell the calendar which model attributes represent the start and end of an event and it can automatically persist changes when an event is moved or resized.

If you don't want changes to happen immediately, you can require confirmation and let the user review the updated dates in the edit action first.

Users can also drag items from outside the calendar onto it.

That opens up workflows like an unscheduled task list beside a calendar where users simply drag work onto the day or person responsible for it.

Resource calendars can do the same thing when moving events between rooms, employees, machines or other resources.

Resource calendars are much easier to build

For applications using FullCalendar's resource views, v5 introduces a proper PHP API for providing resources.

Rooms, employees, vehicles, machines or anything else represented by a resource can now be returned directly from the widget.

The calendar understands when an event moves between resources and can persist that relationship automatically.

Resource data can also be refreshed independently from events.

Bring other calendars into yours

v5 can display external calendars alongside your application's events.

That includes iCalendar feeds and Google Calendar.

So a booking calendar could, for example, display public holidays, a shared company calendar or another external schedule without having to import those events into your own database.

External calendars remain separate and read-only.

Private iCalendar addresses are fetched by your application rather than exposed directly to the browser.

More control, less JavaScript

There are now PHP methods for navigating and controlling the calendar directly.

You can move to a date, change views, navigate forward or backward, scroll to a time, change options and refresh events or resources.

For cases where JavaScript really is the right tool, v5 also provides a cleaner way to register FullCalendar callbacks.

The idea isn't to hide FullCalendar.

It's to make the common things feel natural in Filament while still giving you access to FullCalendar when you need it.

Better defaults for real applications

There are a lot of smaller additions in v5 that become very useful once a calendar is running in production.

Calendars can now be made completely read-only.

You can choose a different initial view on mobile devices.

Events can refresh automatically on an interval.

Calendars correctly resize when they are first rendered inside hidden tabs or modals.

SPA navigation is handled properly.

Multiple calendars on the same page can be controlled independently.

And loading events now has a proper loading state.

Security and tenancy are part of the calendar now

v5 also tightens several areas that previously required developers to be more careful themselves.

Filament model policies are respected by the calendar's view, create, edit and delete actions.

Applications using Filament tenancy automatically scope calendar records to the current tenant.

And operations such as moving, resizing or selecting dates are validated on the server as well as in the browser.

These aren't particularly flashy features, but they're important ones.

A better experience for package authors and tests too

There's now a dedicated Artisan generator for creating FullCalendar widgets.

It can ask for your panel, resource, model and date attributes and generate a working starting point for you.

v5 also introduces dedicated Livewire testing helpers for common calendar interactions such as:

  • finding events
  • clicking events
  • dragging events
  • selecting dates
  • testing calendar actions

The package itself now has a test suite running against both Filament 4 and Filament 5 as well.

One script

The plugin ships a single script, with no extra files for your application to serve. It holds FullCalendar 7, the premium views, recurrence, locales, external calendars and all six themes, and weighs about 223 KB gzipped, up from 199 KB in v4.

And a lot of things were fixed along the way

v5 includes fixes for issues around SPA navigation, recurring events, timezones, hidden calendars, all-day events, date selection, external event sources, dark mode, event serialization and more.

Some of these were long-standing edge cases.

Others came directly from issues and discussions opened by people using the plugin in real applications.

Others came directly from issues and discussions opened by people using the plugin in real applications.

Thank you to everyone who reported them, tested fixes, opened pull requests, shared workarounds or simply explained where the plugin was getting in their way.

Upgrading

I've tried to keep breaking changes to the minimum necessary so upgrading from v4 is as painless as possible, while still giving the plugin room to move forward.

To make it even easier, v5 ships with an automated upgrade script that rewrites most v4 calendar widgets and their tests to the v5 API using Rector, without needing the application to boot:

composer require saade/filament-fullcalendar:"^5.0"
composer require rector/rector:^2.5 --dev --no-scripts
vendor/bin/filament-fullcalendar-v5

The first Composer command may end with an error, and that's expected. The package is installed first, then Laravel's package discovery may try to load your existing v4 widgets before they've been upgraded. Installing Rector with --no-scripts prevents that discovery from running again, and the upgrade script
can then do its work.

The script handles the main mechanical changes required for v5, including handler signatures, record APIs, deprecated actions, getFormSchema(), test calls, and optionally preserving the create button behavior from v4. You can also run it with --dry-run first to see what would change. When it finishes, it
prints a checklist of anything that may still need manual attention.

FullCalendar 7 renamed a lot of options, event fields and render hooks, and the plugin translates the old names for you, so things like eventClassNames, customButtons, buttonText, slotLabelFormat or backgroundColor on an event keep working. A few things need your attention:

  • CSS written for FullCalendar's elements. FullCalendar 7 generates its class names and replaced its --fc-* variables, so selectors such as .fc-daygrid-event match nothing. A few of the old class names, such as fc-event and fc-daygrid-day, are put back on their elements for now. Use FullCalendar's
    class-name options instead, such as eventClass or dayCellClass.
  • Moment format strings. The moment plugin is gone, so a format such as 'titleFormat' => 'MMMM YYYY' no longer works. Use a date formatting object instead.
  • FullCalendar Premium's open-source key. It changed from GPLv3 to AGPLv3. If you used GPL-My-Project-Is-Open-Source, the new key is AGPL-My-Frontend-And-Backend-Are-Open-Source, which requires both your frontend and your backend to be open source.

After updating, publish the new script and rebuild your theme:

php artisan filament:assets
npm run build

Please read the upgrade guide before updating. v5 changes some existing behavior and APIs in addition to adding all of the features above.

This is the direction going forward

Filament FullCalendar started as a relatively small integration between Filament and FullCalendar.

Over time, people started building much more serious scheduling interfaces with it.

v5 reflects that.

Instead of treating FullCalendar as a JavaScript component with a Filament wrapper around it, the plugin now tries to connect the two ecosystems properly.

Filament provides the actions, forms, infolists, policies, colors, filters, tabs and application structure.

FullCalendar provides an extremely capable calendar engine.

Filament FullCalendar should be the bridge between them.

And v5 is a pretty big step in that direction.

Compatibility

Filament FullCalendar v5 supports:

  • Filament 4 and 5
  • FullCalendar 7
  • PHP 8.2+

Full documentation, examples and the complete changelog are available in the repository.

And finally, thank you to everyone who has kept using, contributing to, and believing in Filament FullCalendar despite the, let's call it, less-than-ideal maintenance cycle over the last while. 💛

I'm excited to finally get v5 into your hands.

Full Changelog: v4.0.1...v5.0.0

Don't miss a new filament-fullcalendar release

NewReleases is sending notifications on new releases.