Calendar

A date field component that allows users to enter and edit date.

Component Code
<april:calendar class="rounded-md border" mode="single" :selected="now()" />

The calendar supports single, multiple, and range selection, keyboard navigation, month/year controls, and disabled-date matchers.

Prop Type Description
mode "single" | "multiple" | "range" Selection mode. Defaults to single.
selected string | Date | mode-specific array Initial selection.
disabled array Disabled-date matchers.
required boolean Prevent clearing the current selection.

Common configurations

The default calendar keeps the original April UI appearance. These options add common shadcn calendar variants without requiring a different component.

Prop Type Description
captionLayout "label" | "dropdown" | "dropdown-months" | "dropdown-years" Text labels or native month/year selectors.
showOutsideDays boolean Render days from adjacent months. Defaults to true.
fixedWeeks boolean Keep six rows for a stable height. Defaults to true.
showWeekNumber boolean Add ISO week numbers to the grid.
numberOfMonths int Render up to twelve consecutive months.
pagedNavigation boolean Move by the number of visible months.
weekStartsOn 0– 6 First weekday ( 0 is Sunday).
defaultMonth string | Date Month shown when no selection exists.
fromMonth / startMonth string | Date Earliest navigable month.
toMonth / endMonth string | Date Latest navigable month.
fromYear / toYear int Bounds for the year dropdown.
hideNavigation boolean Hide previous/next controls.

The component dispatches value-change with { detail: { value } }. The existing change and select events remain available:

<april:calendar
captionLayout="dropdown"
:showWeekNumber="true"
:showOutsideDays="false"
:fromYear="now()->subYears(2)->year"
:toYear="now()->addYears(2)->year"
@value-change="console.log($event.detail.value)"
/>

Dropdown caption and week numbers

Component Code
<april:calendar
class="rounded-md border"
captionLayout="dropdown"
:showOutsideDays="false"
:showWeekNumber="true"
:fromYear="now()->subYears(2)->year"
:toYear="now()->addYears(2)->year"
:defaultMonth="now()->startOfMonth()"
/>

Multiple months

Component Code
<april:calendar
class="rounded-md border"
:numberOfMonths="2"
:pagedNavigation="true"
:showWeekNumber="true"
:showOutsideDays="false"
:defaultMonth="now()->startOfMonth()"
/>

Selection modes

Single mode

When mode="single", one day can be selected at a time. The select event's $event.detail.value contains a JavaScript Date or null.

Component Code
<div x-data="{value: null}" class="max-w-72">
<april:calendar class="rounded-md border" mode="single" :selected="now()" @value-change="value = $event.detail.value" />
<p x-text="value ? 'Selected date is '+value : 'No Date Is Selected' " class="my-2 w-full"></p>
</div>

Prop Type Description
@select Alpine event listener Runs when the selected day changes.
required boolean Ensures a selected day cannot be cleared.

Multiple mode

When mode="multiple", users can select several days. The event value is an array of JavaScript Date objects.

Component Code
<div x-data="{ value: [] }" @value-change="value = $event.detail.value" class="flex max-w-72 flex-col items-center">
<april:calendar class="rounded-md border" mode="multiple"
:selected="[now(), now()->addDays(2), now()->addDays(14)]"
/>
<p x-text="'Selected dates are '+value.toString()" class="my-2 wrap-break-word"></p>
</div>

Use max to limit the number of selected days.

<april:calendar mode="multiple" max="5" />

Component Code
<div x-data="{ value: [] }" @value-change="value = $event.detail.value" class="flex max-w-72 flex-col items-center">
<april:calendar class="rounded-md border" mode="multiple" max="5"
:selected="[now(), now()->addDays(2), now()->addDays(14)]"
/>
<p x-text="'Selected dates are '+value.toString()" class="my-2 wrap-break-word"></p>
</div>

Range mode

When mode="range", the event value is an object with from and to JavaScript Date values. min and max limit the number of days between the endpoints.

Component Code
<div x-data="{ value: { from: null, to: null } }" @value-change="value = $event.detail.value" class="flex w-full max-w-72 flex-col items-center">
<april:calendar class="rounded-md border" mode="range" :selected="['from' => now(), 'to' => now()->addDays(14)]"
/>
<p x-text="'Selected range is from '+value['from']+' to '+value['to']" class="my-2 wrap-break-word"></p>
</div>

Use min and max to constrain the length of the selected range:

<april:calendar mode="range" min="3" max="14" />

Component Code
<div x-data="{ value: { from: null, to: null } }" @value-change="value = $event.detail.value" class="flex w-full max-w-72 flex-col items-center">
<april:calendar class="rounded-md border" mode="range" :selected="['from' => now(), 'to' => now()->addDays(14)]"
max="15" min="6" />
<p x-text="'Selected range is from '+value['from']+' to '+value['to']" class="my-2 wrap-break-word"></p>
</div>

Disabling dates

Pass an array of matcher objects to disabled. A dates matcher disables exact dates, before/ after disables a range (the boundary itself remains enabled), and dayOfWeek accepts a number or an array from 0 (Sunday) to 6 (Saturday).

Laravel serializes now() on the server. April converts ISO timestamps to the visitor's local calendar date in the browser, so a date-only rule such as now() follows the user's local day. If your application stores a timezone per user, apply it before building the value, for example now()->setTimezone($user->timezone).

Component Code
<april:calendar class="rounded-md border" mode="single" :disabled="['dates' => [now()]]" />
Component Code
<april:calendar class="rounded-md border" mode="single"
:disabled="['before' => now(), 'after' => now()->addDays(10)]" />

Disable the worst day of the week

Component Code
<div class="flex flex-col items-center gap-2 text-center">
<p>Disable the worst day of the week</p>
<april:calendar class="rounded-md border" mode="single" :disabled="['dayOfWeek' => 1]" />
</div>
Component Code
<april:calendar class="rounded-md border" mode="single" :disabled="[
['before' => now()->subDays(10), 'after' => now()->addDays(10)],
['dates' => [now(), now()->subDays(1)]],
['dayOfWeek' => 3],
['dayOfWeek' => 5]
]" />

The same matcher types can be used independently:

<april:calendar :disabled="[
['dates' => [now(), now()->addDay()]],
['before' => now()],
['dayOfWeek' => [0, 6]],
]" />

Publishing Views

Use the following command to publish this view:

php artisan april:publish calendar
April UI keeps package views in `vendor/` by default. The command uses Laravel's vendor publishing system and copies overrides to `resources/views/vendor/april/components`. To publish all components, run:
php artisan april:publish --all
Review local overrides after an upgrade with `php artisan april:update --diff`.