Kalendar

Views#

Kalendar's nine views are standalone composables. You call KalendarMonth(...) directly — there is no Kalendar(type = ...) dispatcher any more (see Migration from 1.x).

They all live in com.himanshoe.kalendar, share the same KalendarViewConfig, resolve their visuals through the same KalendarTheme, and take the same events list — generic in your event type, so every callback hands it back without a cast.

Underneath, every one of them is built on the public headless engine — the same KalendarPager, monthGridDates and scheduleBlocks you would use to build a calendar we did not design.

What they look like#

Every picture below is drawn by the library itself when this site is built — same composables, same default theme, same events — so none of them can drift from the code they document. Each follows the light/dark switch in the top bar.

The gallery covers the seven views with generated screenshots. Two more ship in 2.0.0 and are not pictured here — see the API reference for both:

  • KalendarResourceView — one day, one column per resource. A room board, a chair schedule, a vehicle roster. Events reach their lane through a resourceIdOf accessor, and a drag moves an event in time and between lanes.
  • KalendarDatePicker — a compact single-month picker, the calendar that drops out of a form field. A month and year control you can jump decades with, and a Clear/Today action rail.

Choosing one#

ViewShapePaging unitState factory
KalendarWeekOne week rowWeekrememberKalendarWeekState
KalendarMonthMonth gridMonthrememberKalendarMonthState
KalendarYear12 month grids in a lazy scrolling columnYearrememberKalendarYearState
KalendarTimelineContinuous month listnone — free scrollrememberKalendarTimelineState
KalendarScheduleHourly grid for one dayDayrememberKalendarScheduleState
KalendarScheduleWeekHourly grid, 7 day columnsWeekrememberKalendarWeekState
KalendarResourceViewHourly grid, one lane per resourceDayrememberKalendarScheduleState
KalendarAgendaEvent list grouped by datenone — free scrollrememberLazyListState
KalendarDatePickerCompact single-month pickerMonthrememberKalendarMonthState

What they have in common#

Date-grid viewsKalendarWeek, KalendarMonth, KalendarYear, KalendarTimeline — render day cells, take selectedDates / onDateClick, and show events as indicator dots — with a span bar for anything covering more than one day.

Hour-grid viewsKalendarSchedule, KalendarScheduleWeek and KalendarResourceView — render an hourly time grid, take onEventClick plus a change callback, and lay events out as duration-sized blocks packed side by side where they overlap. They have no concept of date selection. All three honour KalendarViewConfig.scheduleVisibleHours, so a business-hours calendar is one config value.

The agendaKalendarAgenda — has no grid and no pager at all: it lists the events themselves, grouped by date, and skips every date that has none. It takes onEventClick and, like the Schedule views, has no concept of date selection.

Feature matrix#

FeatureWeekMonthYearTimelineScheduleScheduleWeekResourceAgendaDatePicker
Arrow + swipe navigationyesyesyesnoyesyesarrows onlynoarrows only
Today buttonyesyesyesyesyesyesyesnoaction rail
Month/year jump pickeryesyesyesnoyesyesyesnoits own header
selectedDates / onDateClickyesyesyesyesnonononoyes
Sliding selection indicatoryesyesnonononononono
Drag-to-select a rangeyesyesnonononononono
Drag events to a new datenoyesnonononononono
Drag / resize event blocksnonononoyesyesyesnono
Drag an event between columnsnononononodayslanesnono
Sweep out a new eventnonononoyesyesnonono
Event indicator dots, span bars and +Nyesyesyesyesnonononono
visibleDaysOfWeek work weeksyesyesyesyesnoyesnonoyes
scheduleVisibleHours business hoursnonononoyesyesyesnono
dayContent slotyesyesyesyesnonononoyes
header slotyesyesyesyesnonononoyes
dayOfWeekLabel slotyesyesyesyesnonononoyes
Event / hour / now-indicator slotsnonononoyesyesyesnono
dateHeader / eventContent / emptyState slotsnonononononopartlyyesno
eventLoader and the loadingContent slotyesyesyesyesyesyesyesyesno

KalendarTimeline scrolls continuously, so it has no pages and no arrow buttons — its header slot receives a scope whose page vocabulary is mapped onto months, and KalendarViewConfig.showNavigationArrows and showJumpPicker are ignored there.

The Schedule views draw the built-in navigation header directly and do not expose a header slot; style it through KalendarTheme instead. They do expose slots for everything inside the grid — see Customization.

The state factories#

Each factory wraps a PagerState (or a LazyListState for the timeline) and exposes it in date terms. All of them share the same five parameters, except rememberKalendarScheduleState, which has no startDayOfWeek — a single day has no week columns to align.

ParameterTypeDefaultDescription
initialDateLocalDatetoday, system time zoneThe week / month / year / day initially visible.
startDayOfWeekDayOfWeekDayOfWeek.MONDAYThe first week column. Not on rememberKalendarScheduleState.
minDateLocalDate?nullLower bound. Unbounded when null.
maxDateLocalDate?nullUpper bound. Unbounded when null.
timeSourceKalendarTimeSourcethe ambient oneWhere the state reads "today" from — the seam between the calendar and the wall clock.

initialDate itself defaults to today as read through timeSource, so wrapping a screen in ProvideKalendarTimeSource(fixed) { … } pins every view's idea of the current date at once: the today highlight, the today button's target, and the Schedule views' now-indicator. That is how the screenshots on this page are made — a fixed clock, so the pictures cannot drift. See The clock.

KalendarViewState#

Returned by rememberKalendarWeekState, rememberKalendarMonthState, rememberKalendarYearState, and rememberKalendarScheduleState.

MemberTypeDescription
visibleDateLocalDateStart date of the page currently on screen.
startDayOfWeekDayOfWeekThe week's first column.
minDate / maxDateLocalDate?The bounds this state was created with.
canScrollBackwardBooleanWhether stepping one page back stays within minDate.
canScrollForwardBooleanWhether stepping one page forward stays within maxDate.
timeSourceKalendarTimeSourceWhere this state reads "today" from. Read-only, but snapshot-backed: the remember*State factory keeps it in step with the ambient source without recreating the state and losing the scroll position. Choose the source by passing it to the factory.
suspend animateScrollTo(date)UnitAnimates to the page containing date, clamped to the bounds.
suspend animateScrollToToday()UnitAnimates to the page containing today, clamped.
suspend animateToPreviousPage()UnitOne page back. A no-op past minDate.
suspend animateToNextPage()UnitOne page forward. A no-op past maxDate.

KalendarTimelineState#

Returned by rememberKalendarTimelineState.

MemberTypeDescription
visibleDateLocalDateStart of the month currently topmost in the list.
startDayOfWeekDayOfWeekThe week's first column.
minDate / maxDateLocalDate?The bounds this state was created with.
suspend animateScrollTo(date)UnitAnimates so the month containing date reaches the top.
suspend animateScrollToToday()UnitAnimates back to today's month.
timeSourceKalendarTimeSourceWhere this state reads "today" from. Read-only, for the same reason as KalendarViewState.timeSource.

Warning: minDate / maxDate bound the buttons, not the swipe. On the paged views the bounds disable the header's arrow buttons and clamp animateScrollTo, but a swipe is not blocked and can carry you past them. On KalendarTimeline the bounds do clamp the scroll itself, because the list is built with a finite item count.

KalendarAgenda has neither: it takes a plain LazyListState, because a list of events has nothing to page through and nothing to bound.

Both state classes are thin wrappers over the engine's KalendarPager and a Compose scroll state. Every member above is documented signature-by-signature in the state reference.