Calendar
Calendar shows events in a month, a week of dates and a day. This is different from the Datepicker, which is a small popup that appears next to a text field so someone can type or pick a single date for a form. Use Calendar when you want to show a schedule, a set of events, or a range of days that someone can look at and pick from directly.
The component requires a name,
which is used internally to keep track of the calendar and, later on, to call JavaScript helper functions on it.
It needs a label, which screen readers announce so a visually
impaired visitor knows what the grid in front of them is for. Everything else, including the list of events, is optional.
| Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|---|---|---|---|---|---|---|
|
30
|
31
|
1
|
2
|
3
|
4
|
5
Sprint planning
|
|
6
|
7
|
8
|
9
|
10
|
11
|
12
Team offsite
|
|
13
Team offsite
|
14
Team offsite
|
15
|
16
|
17
|
18
|
19
Design review
Deploy freeze
Client call
Retro
9:00am Standup
9:30am Design sync
2:00pm Kenya project review
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
1
|
2
|
3
|
// this data powers the calendar above
$teamEvents = [
['date' => now()->startOfMonth()->addDays(4)->toDateString(), 'label' => 'Sprint planning', 'type' => 'info'],
['date' => now()->startOfMonth()->addDays(11)->toDateString(), 'end' => now()->startOfMonth()->addDays(13)->toDateString(), 'label' => 'Team offsite', 'type' => 'success'],
['date' => now()->startOfMonth()->addDays(18)->toDateString(), 'label' => 'Design review', 'type' => 'warning'],
['date' => now()->startOfMonth()->addDays(18)->toDateString(), 'label' => 'Deploy freeze', 'type' => 'danger'],
['date' => now()->startOfMonth()->addDays(18)->toDateString(), 'label' => 'Client call', 'type' => 'info'],
['date' => now()->startOfMonth()->addDays(18)->toDateString(), 'label' => 'Retro', 'type' => 'info'],
['date' => now()->format('Y-m-d').' 09:00', 'end' => now()->format('Y-m-d').' 10:00', 'label' => 'Standup', 'type' => 'info'],
['date' => now()->format('Y-m-d').' 09:30', 'end' => now()->format('Y-m-d').' 10:30', 'label' => 'Design sync', 'type' => 'success'],
['date' => now()->format('Y-m-d').' 14:00', 'end' => now()->format('Y-m-d').' 15:30', 'label' => 'Kenya project review', 'type' => 'warning'],
];
<x-bladewind::calendar name="team-cal" label="Team calendar" :events="$teamEvents" />
Views
The view attribute controls how much of the calendar Calendar shows at once.
It accepts month, week, or day.
If you do not set it, Calendar shows month view first, and the three buttons in the header let a visitor switch between views.
The date attribute tells Calendar which day to center the view on. It should be written as Y-m-d, for example 2026-08-14, and it defaults to today's date if you leave it out. In month view, Calendar shows the whole month that date falls in. In week view, Calendar shows the seven days of the week that date falls in. In day view, Calendar shows only date itself.
Week view and day view are not simply shorter versions of month view. They are a full hour by hour schedule, similar to the week and day views you would see in Outlook or Google Calendar, and they share the exact same grid, except, day view is just narrowed down to one column instead of seven. There is more about how that works a little further down this page.
Today's date is always announced to screen readers, but Calendar leaves it visually plain by default. Set highlight-today="true" to tint today's date in month view and today's whole column in week and day view, so it stands out at a glance.
Selection
The selectable attribute controls whether dates can be selected. It supports three values:
- * none — The default. Dates cannot be selected.
- * single — Selects one date at a time. Choosing another date replaces the current selection.
- * multiple — Selects multiple dates. Clicking a selected date again removes it.
Use the selected attribute to define dates that should be selected initially. It accepts a single date in Y-m-d format, a comma-separated list of dates, or an array of dates.
When selection is enabled, Calendar automatically creates hidden form fields using the name attribute. For multiple selections, [] is appended to the field name. This means selected dates are included automatically when the surrounding form is submitted, with no additional code required. Try selecting a few dates below to see how it works.
| Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|---|---|---|---|---|---|---|
|
30
|
31
|
1
|
2
|
3
|
4
|
5
|
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
1
|
2
|
3
|
<x-bladewind::calendar
name="availability"
selectable="multiple"
label="Mark your availability"
:selected="[now()->addDays(2)->toDateString(), now()->addDays(5)->toDateString()]" />
range option already does it well, and it is built for exactly that job: a date range typed into a form field. Calendar is meant for looking at a whole month or week and picking individual days out of it, not for choosing a single continuous range.Events
You give Calendar its events through the events attribute, which is an array. Each item in the array is itself a small array describing one event, and it can have these fields: date, end, label, type, and href.
| Field | Description |
|---|---|
label |
is the text shown for the event |
type |
controls its color, and it accepts info, success, warning, or danger |
href |
is optional. If you set it, the event becomes a real clickable link that takes a visitor to that address, which is useful for linking an event straight to its detail page somewhere else in your application. |
date |
the date on which an event occurs or should be displayed |
end |
date on which event ends. For multiday events. |
description |
is optional. If you set it, the event's marker becomes a button that opens a details drawer instead of a plain link or piece of text. See Event Details Drawer below. |
Event Dates
The date field can be written two different ways, and which way you choose changes how the event behaves.
If you write date as just a day, like 2026-08-14, the event is an all day event. It does not belong to any particular hour. All day events show up as a small colored marker on that day in month view. If you also set end as a day, the event stretches across every day from date to end, which is useful for things like a multi day conference or someone being on leave for a week. The team offsite in the very first example on this page works this way.
If you write date with a time attached, like 2026-08-14 15:00, the event is a timed event. Timed events are meant for meetings and appointments that happen at a specific hour. If you set end too, also with a time on the same day, that tells Calendar exactly how long the event lasts. If you leave end out, Calendar assumes the event lasts one hour. Timed events show up in month view too, as a marker with the start time written in front of the label, for example "3:00pm Kenya project review", but they only get positioned properly on a real hour by hour timeline once you switch to week view or day view.
Because a day in month view is small, Calendar only shows a limited number of markers on each day before it starts hiding the rest. This limit is set by max-events-per-day, which defaults to 3. When a day has more events than that, the extra ones are tucked behind a "+N more" button. That button is a real, ordinary button that can be reached with the keyboard and clicked or pressed to reveal the rest, rather than a decoration that only works with a mouse.
Event Details Drawer
Give an event a description and its marker turns into a button. Clicking it opens a drawer showing the event's date and time, its label, the description you gave it, and, if you also set href, a "View full details" link to send the visitor to that event's own page. Nothing needs to be turned on for this. It happens automatically for any event that has a description, in month view, week view, and day view alike.
This drawer stays inside the calendar's own box rather than covering the whole page, and it does not dim or block the rest of the calendar behind it. That means you can click straight from one event to the next and the drawer's content just swaps, without having to close it first. Escape or its own close button dismiss it.
| Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|---|---|---|---|---|---|---|
|
30
|
31
|
1
|
2
|
3
|
4
|
5
|
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
1
|
2
|
3
|
<x-bladewind::calendar
name="team-calendar"
:events="[
[
'date' => '2026-08-14 11:00',
'end' => '2026-08-14 11:30',
'label' => 'Design review',
'type' => 'info',
'href' => '/component/calendar',
'description' => "Walk through the new event details drawer with the team.\nBring the latest screenshots.",
],
]" />
Week and Day View
Switching the calendar to week view replaces the month grid with a detailed weekly schedule. Each of the seven days has its own column, while the hours run vertically from midnight to midnight. All-day and multi-day events appear in a dedicated row at the top, keeping them separate from events scheduled for specific times.
Day view uses the same layout but focuses on a single day, giving it a wider column and more space to view the day’s schedule in detail.
The example below opens in week view with some sample meetings. Notice that two events on the first day overlap. Instead of hiding one behind the other, the calendar displays them side by side, making both events easy to see and access.
<x-bladewind::calendar
name="week-demo" label="Week demo calendar" view="week" :events="$teamEvents" />
Week and day views do not open at midnight. Since most events happen during the day, the calendar automatically scrolls to a practical morning hour, bringing the most relevant part of the schedule into view immediately.
The example below shows the same meetings in day view. Overlapping events are displayed side by side, just as they are in week view. Both views use the same underlying layout, with day view simply displaying one wider column instead of seven.
$weekAnchor = now()->startOfWeek();
<x-bladewind::calendar
name="day-demo" label="Day demo calendar" view="day" :events="$teamEvents"
:date="$weekAnchor->copy()->addDays(1)->toDateString()" />
Restricting Dates
Sometimes you need to stop a visitor from picking certain dates. min-date and max-date set the earliest and latest dates Calendar will allow someone to navigate to or select, which is useful for things like a booking calendar that should not allow dates in the past. disabled-dates lets you turn off specific individual dates within that range too, for example public holidays or days that are already fully booked. Dates that are disabled, whether by the range or by the list, are still shown and can still be reached with the arrow keys, but a visitor cannot click or press Enter to select them.
| Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|---|---|---|---|---|---|---|
|
30
|
31
|
1
|
2
|
3
|
4
|
5
|
|
6
|
7
|
8
|
9
|
10
|
11
|
12
|
|
13
|
14
|
15
|
16
|
17
|
18
|
19
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
1
|
2
|
3
|
<x-bladewind::calendar name="booking" label="Booking calendar"
selectable="single"
:min-date="now()->toDateString()"
:max-date="now()->addDays(20)->toDateString()"
:disabled-dates="[now()->addDays(3)->toDateString(), now()->addDays(4)->toDateString()]" />
By default, month view also shows a few grayed out days from the previous and next month so every row of the grid stays full. This is controlled by show-other-month-days, which is true unless you turn it off. Setting it to false leaves those cells empty instead of showing the neighboring month's dates.
Fixed Height
Calendar maintains a consistent height across month, week, and day views by default. Without this, its size would change whenever you switched views or moved between months, causing the surrounding page content to shift. By default, Calendar reserves 40rem, enough space for a six-week month. When the current view needs less space, the remaining area is left empty rather than shrinking the calendar. If the content needs more space, the calendar scrolls internally instead of growing beyond its set height.
You can customize the height using the height attribute. Example height="28rem". To let Calendar grow and shrink naturally based on its content, pass an empty value: height=""
| Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday |
|---|---|---|---|---|---|---|
|
30
|
31
|
1
|
2
|
3
|
4
|
5
Sprint planning
|
|
6
|
7
|
8
|
9
|
10
|
11
|
12
Team offsite
|
|
13
Team offsite
|
14
Team offsite
|
15
|
16
|
17
|
18
|
19
Design review
Deploy freeze
Client call
Retro
9:00am Standup
9:30am Design sync
2:00pm Kenya project review
|
|
20
|
21
|
22
|
23
|
24
|
25
|
26
|
|
27
|
28
|
29
|
30
|
1
|
2
|
3
|
This height rule also applies inside a single day. Each day cell has a fixed height regardless of how many events are packed into it, so one busy day never pushes its own row taller than the days next to it. If a day has more events than max-events-per-day and someone opens its "+N more" button, the extra events appear in their own small scrolling list inside that one cell, rather than making the whole row grow and pushing every other row down the page.
Navigation
The Previous, Next, and Today buttons in the header, along with Page Up and Page Down on the keyboard, move
Calendar to a different period. Which period depends on the current view: a day at a time in day view, a
week at a time in week view, a month at a time in month view. By default this all happens instantly in the
browser, using the same list of events you already gave it, without needing to reload the page or wait on
a request to your server. If you would rather have your own server decide what to show next instead, for
example because you are loading a very large or constantly changing set of events,
set client-navigation="false". With that turned off, navigating only
sends out the before-navigate and navigate events
described below, and your application is responsible for showing the new period, whether that means loading a fresh page or updating things yourself with Livewire or Inertia. Data Grid offers this same choice for its own sorting and searching, if you have used that component before.
Keyboard Interaction
Calendar's grid follows the same accessible pattern used elsewhere in this library: a single Tab stop gets a visitor into the grid, and from there the arrow keys move around inside it, rather than needing to Tab through every single day one at a time. In week view and day view, the same keys move between the day headers running along the top of the grid rather than between day cells, since these views no longer have day cells in the month view sense. Day view has only one day header, so left and right simply move to the previous or next day, bringing it into view.
| Key | Action |
|---|---|
| ← → ↑ ↓ | Move focus by one day, or by seven days at once for up and down. Moving past the edge of what is currently visible navigates to bring the next day into view. |
| Home / End | Jump to the first or last day of the current row. |
| Page Up / Page Down | Go to the previous or next day in day view, week in week view, or month in month view. |
| Shift + Page Up / Page Down | Go one level further than Page Up and Page Down alone: a week at a time in day view, a month at a time in week view, or a year at a time in month view. |
| Enter / Space | Select the day currently focused, if selection is turned on. |
Every event marker, including the timed events placed on week view and day view's hour by hour grid, is a genuine link or button that can be reached with an ordinary Tab press and activated like any other control on the page. Nothing here is a decoration that only responds to a mouse.
JavaScript Events
Calendar announces what it is doing by firing browser events, which your own JavaScript can listen for. Events whose name starts with "before" are cancelable, meaning you can call preventDefault() on them inside your listener to stop whatever change was about to happen. Every event name Calendar uses starts with bladewind:calendar:.
| Event suffix | When it runs |
|---|---|
before-navigate, navigate | Just before, and then just after, the visible day, week, or month changes. |
before-view-change, view-change | Just before, and then just after, switching between month view, week view, and day view. |
before-select, select | Just before, and then just after, the selected date or dates change. |
Full List of Attributes
| Attribute | Default | Description |
|---|---|---|
| name | Generated | Unique identifier used internally and, when selectable, as the name of the posted form field. |
| label | Calendar | Accessible name announced by screen readers for the grid. |
| view | month | month, week, or day. |
| date | today | Anchor date (Y-m-d) for the month, week, or day initially shown. |
| week-starts | sunday | sunday or monday. |
| selectable | none | none, single, or multiple. |
| selected | [] | Date or dates selected at the start: a Y-m-d string, a comma-separated string, or an array. |
| min-date | null | Earliest date a visitor can navigate to or select. |
| max-date | null | Latest date a visitor can navigate to or select. |
| disabled-dates | [] | Specific dates to turn off regardless of the min and max range. |
| events | [] | Array of event descriptors, each with date, end, label, type, and href fields. |
| max-events-per-day | 3 | How many event markers a day shows in month view before the rest are tucked behind "+N more". |
| show-other-month-days | true | Whether to fill the grid with dimmed, disabled days from the neighboring months. |
| show-week-numbers | false | Whether to show an ISO week number next to each row. |
| highlight-today | false | Whether to tint today's date in month view and today's whole column in week and day view. |
| height | 40rem | Fixed height for the grid, with its own scrollbar if the content needs more room. Pass an empty value to size the calendar naturally instead. |
| client-navigation | true | Whether navigating rebuilds the grid in the browser automatically. Set to false to hand navigation off to your own server-driven calendar. |
| today-label | Today | Text label for the jump-to-today button. |
| previous-label | Previous | Accessible label for the previous-period button. |
| next-label | Next | Accessible label for the next-period button. |
JavaScript API
Every helper function listed here returns true once it succeeds, or if the state it was asked for was already true. It returns false if the calendar it was pointed at could not be found, or if a cancelable event you are listening for called preventDefault() and stopped the change from happening.
nextCalendarPeriod('team-calendar');
previousCalendarPeriod('team-calendar');
goToCalendarToday('team-calendar');
goToCalendarMonth('team-calendar', 2026, 12);
setCalendarView('team-calendar', 'week');
selectCalendarDate('team-calendar', '2026-08-14');
clearCalendarSelection('team-calendar');
calendarSelectedDates('team-calendar'); // ['2026-08-14']
Calendar with all attributes defined
<x-bladewind::calendar
name="team-calendar"
label="Team calendar"
view="week"
date="2026-08-14"
week-starts="monday"
selectable="multiple"
:selected="['2026-08-10', '2026-08-14']"
min-date="2026-01-01"
max-date="2026-12-31"
:disabled-dates="['2026-12-25']"
:events="[
[
'date' => '2026-08-14 15:00',
'end' => '2026-08-14 16:00',
'label' => 'Sprint planning',
'type' => 'info',
'href' => '/events/sprint-planning',
'description' => 'Review the roadmap and assign owners for Q3.',
],
]"
max-events-per-day="3"
show-other-month-days="true"
show-week-numbers="false"
highlight-today="true"
height="40rem"
client-navigation="true"
today-label="Today"
previous-label="Previous"
next-label="Next"
class="shadow-sm" />
resources > views > components > bladewind > calendar.blade.php