CalendarView
CalendarView renderiza agendas de eventos no horário local como visualização de dia, semana ou mês. Escolha-o quando pessoas precisam inspecionar posição de eventos e disponibilidade; escolha Calendar quando a tarefa é selecionar datas, não ler uma agenda.
Exemplos
Grade semanal e de horas
Chips de evento são medidos em relação ao contêiner de scroll real, para que um popover opcional seja posicionado ao lado do chip. Os cinco tipos usam cor e forma distintas: sessão sólida, sessão de programa sólida, pendente tracejado, bloqueio hachurado e externo contornado.
Visão geral mensal
Células mensais mostram até três eventos e depois um indicador de quantidade restante. Selecionar um dia muda para sua visualização diária, mantendo a data ancorada no horário local.
Quando usar
Use CalendarView para navegar por eventos locais concretos, janelas de disponibilidade e espaço livre na grade de horas.
Limitações: eventos sobrepostos no mesmo dia ficam empilhados em largura total; CalendarView não os organiza em colunas. Um evento que cruza meia-noite é renderizado apenas no seu dia local de início. Arrastar eventos e a navegação de grade por teclado pertencem à aplicação.
Prefira outro componente quando:
- A pessoa seleciona uma data ou intervalo de datas — use Calendar ou DatePicker.
- Pessoas precisam reservar um instante disponível — use SlotPicker.
- A tarefa é definir disponibilidade recorrente — use WeeklyScheduleEditor.
Acessibilidade
- Anterior, Hoje e próximo são botões nativos nomeados. Dia, Semana e Mês são botões em um grupo nomeado e
expõem a visualização ativa com
aria-pressed. - Chips de evento são botões nativos com data, hora e título localizados no nome acessível. Um popover opcional é um diálogo nomeado; ele fecha com Escape, interação de ponteiro fora ou resize para não manter medições antigas.
- Clicar no espaço vazio da grade de horas é deliberadamente apenas para ponteiro e chama
onSlotCreatecom um Date local ajustado. Chips de evento e todos os controles da toolbar permanecem acessíveis por teclado. - CalendarView não emite landmark de página nem heading, portanto pode ficar dentro do outline do documento da
página consumidora. Use
labelselocalepara traduzir controles e formatação de datas.
API e código
Blade: Adiado por decisão — CalendarView ainda não tem equivalente em Blade.
| Nome | Tipo | Obrigatória | Descrição |
|---|---|---|---|
view | 'day' | 'week' | 'month' | — | Controlled displayed view. Default: `"week"`. |
defaultView | 'day' | 'week' | 'month' | — | Initial displayed view when uncontrolled. Default: `"week"`. |
onViewChange | (view: 'day' | 'week' | 'month') => void | — | Called after the displayed view changes. |
date | string | Date | — | Controlled local period anchor as a Date or `YYYY-MM-DD` string. |
defaultDate | string | Date | — | Initial local period anchor as a Date or `YYYY-MM-DD` string. |
onDateChange | (isoDate: string) => void | — | Called with the local `YYYY-MM-DD` anchor after it changes. |
events | CalendarViewEvent[] | — | Events rendered in the visible local day, week, or month. |
availability | Record<number, CalendarViewAvailability[]> | — | Weekly local availability windows keyed by `0` (Sunday) through `6` (Saturday). |
startHour | number | — | First visible hour in day and week grids. Default: `7`. |
endHour | number | — | Hour at which the day and week grids end. Default: `21`. |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6 | — | First weekday, where `0` is Sunday and `6` is Saturday. Default: `1`. |
onEventOpen | (event: CalendarViewEvent) => void | — | Called when an event chip is opened. |
renderEventPopover | (event: CalendarViewEvent, close: () => void) => ReactNode | — | Renders the optional event-summary popover. Receives a close callback. |
onSlotCreate | (start: Date) => void | — | Called with a snapped local Date after an empty hour-grid area is clicked. |
slotStep | number | — | Local-minute increment for empty-grid clicks. Default: `30`. |
toolbarActions | ReactNode | — | Extra content rendered at the end of the toolbar. |
locale | string | — | BCP 47 locale used for all weekday and month formatting. Default: `"en-US"`. |
labels | CalendarViewLabels | — | Translatable visible and accessible labels, merged over English defaults. |
x-data="lyraCalendarView({ … })"
| Opção | Tipo | Obrigatória | Descrição |
|---|---|---|---|
defaultView | View | — | Initial view, default `week`. Can be synchronized with `x-modelable="view"`. |
defaultDate | string | Date | — | Initial local anchor, default today. Can be synchronized with `x-modelable="date"`. |
events | LyraCalendarViewEvent[] | — | |
availability | Record<number, LyraCalendarViewAvailability[]> | — | |
startHour | number | — | |
endHour | number | — | |
weekStartsOn | 0 | 1 | 2 | 3 | 4 | 5 | 6 | — | |
slotStep | number | — | |
locale | string | — | |
labels | LyraCalendarViewLabels | — |
HTML canônico sem runtime de comportamento (forneça o posicionamento de eventos e as interações):
<div class="lyra-calview">
<div class="lyra-calview__toolbar">
<button class="lyra-calview__nav" type="button" aria-label="Período anterior">‹</button>
<span class="lyra-calview__title">agosto de 2026</span>
<span class="lyra-calview__seg" role="group" aria-label="Visualização do calendário"
><button type="button" aria-pressed="true">Semana</button></span
>
</div>
<div class="lyra-calview__grid">
<div class="lyra-calview__col">
<button class="lyra-calview__evt lyra-calview__evt--pending" type="button">
10:00–11:00 Aguardando aprovação
</button>
</div>
</div>
</div>lyraCalendarView anima o HTML servido. Passe events, availability por dia da semana,
startHour, endHour, weekStartsOn, slotStep, locale e labels nas opções. view
(day, week ou month) e date (ISO local) são estados editáveis. defaultView e
defaultDate definem o estado inicial. Use x-modelable="date" na raiz para controlar a
data externamente; um escopo Alpine aninhado pode ligar view com x-modelable="view".
Mudanças externas dos modelos não disparam eventos de interação.
Os eventos na raiz carregam os mesmos valores dos callbacks React: lyra:view-change
leva a visualização, lyra:change leva YYYY-MM-DD local, lyra:event-open leva o objeto
do evento e lyra:slot-create leva um Date local ajustado a slotStep. Ações da toolbar
e conteúdo do popover são markup da aplicação. O popover é posicionado pelo chip e fecha
com pointerdown fora, Escape ou resize. Inclua .lyra-calview__pop quando precisar dele.
<div
class="lyra-calview"
x-data="lyraCalendarView({
defaultDate: '2026-08-12', locale: 'pt-BR', events: calendarEvents,
availability: { 3: [{ start: '08:00', end: '17:00' }] },
labels: {
previous: 'Período anterior',
today: 'Hoje',
next: 'Próximo período',
view: 'Visualização do calendário',
day: 'Dia',
week: 'Semana',
month: 'Mês',
}
})"
x-modelable="date"
x-model="selectedDate"
@lyra:event-open="showEvent($event.detail)"
@lyra:slot-create="createAt($event.detail)"
>
<div class="lyra-calview__toolbar">
<button
class="lyra-calview__nav"
type="button"
:aria-label="label('previous')"
@click="navigate(-1)"
>
‹
</button>
<button
class="lyra-calview__nav"
type="button"
:aria-label="label('today')"
@click="setDate(new Date())"
>
●
</button>
<button
class="lyra-calview__nav"
type="button"
:aria-label="label('next')"
@click="navigate(1)"
>
›
</button>
<span class="lyra-calview__title" x-text="title()"></span>
<span class="lyra-calview__seg" role="group" :aria-label="label('view')">
<button
type="button"
:aria-pressed="view === 'day'"
@click="setView('day')"
x-text="label('day')"
></button>
<button
type="button"
:aria-pressed="view === 'week'"
@click="setView('week')"
x-text="label('week')"
></button>
<button
type="button"
:aria-pressed="view === 'month'"
@click="setView('month')"
x-text="label('month')"
></button>
</span>
<!-- Place application toolbar actions here. -->
</div>
<div x-show="view !== 'month'">
<div class="lyra-calview__head" :style="gridStyle()">
<span></span>
<template x-for="day in days()" :key="day.key"
><span class="lyra-calview__head-cell" :class="dayClass(day)"
><span x-text="weekdayLabel(day)"></span
><strong x-text="day.date.getDate()"></strong></span
></template>
</div>
<div class="lyra-calview__scroll" tabindex="0" aria-label="Horas do calendário">
<div class="lyra-calview__grid" :style="gridStyle()">
<div class="lyra-calview__ruler" :style="{ height: gridHeight() + 'px' }">
<template x-for="hour in hours()" :key="hour"
><span
class="lyra-calview__hour"
:style="hourStyle(hour)"
x-text="String(hour).padStart(2, '0') + ':00'"
></span
></template>
</div>
<template x-for="day in days()" :key="day.key"
><div
class="lyra-calview__col"
:style="{ height: gridHeight() + 'px', backgroundSize: '100% 48px' }"
@click="createSlot($event, day)"
>
<template x-for="(window, index) in day.windows" :key="index"
><span class="lyra-calview__avail" :style="availabilityStyle(window)"></span
></template>
<span
class="lyra-calview__now"
x-show="nowStyle(day)"
:style="nowStyle(day) || {}"
></span>
<template x-for="item in day.events" :key="item.id"
><button
class="lyra-calview__evt"
:class="{ ['lyra-calview__evt--' + item.kind]: true }"
:style="eventStyle(item)"
type="button"
:aria-label="eventLabel(item)"
@click="openEvent($event, item)"
>
<span
class="lyra-calview__evt-time"
x-text="time(item.startDate) + '–' + time(item.endDate)"
></span>
<span
class="lyra-calview__evt-title"
x-show="parseFloat(eventStyle(item).height) >= 34"
x-text="item.title"
></span></button
></template></div
></template>
</div>
<div
class="lyra-calview__pop"
role="dialog"
:aria-label="popover?.event.title"
x-show="popover"
:style="popover ? { top: popover.top + 'px', left: popover.left + 'px' } : {}"
>
<!-- Render popover?.event with application markup. -->
<button type="button" @click="closePopover()">Fechar</button>
</div>
</div>
</div>
<div class="lyra-calview__mgrid" x-show="view === 'month'">
<template x-for="(name, index) in weekdays()" :key="index"
><span class="lyra-calview__head-cell" x-text="name"></span
></template>
<template x-for="day in days()" :key="day.key"
><button
class="lyra-calview__mcell"
type="button"
:class="monthClass(day)"
@click="selectMonthDay(day)"
>
<span class="lyra-calview__mday" x-text="day.date.getDate()"></span>
<template x-for="item in monthEvents(day)" :key="item.id"
><span
class="lyra-calview__mevt"
:class="{ ['lyra-calview__evt--' + item.kind]: true }"
x-text="time(item.startDate) + ' ' + item.title"
></span
></template>
<span
class="lyra-calview__more"
x-show="monthMore(day)"
x-text="'+' + monthMore(day)"
></span></button
></template>
</div>
</div>