useCalendarApp Reference

useCalendarApp(config: CalendarAppConfig) is the hook that connects the DayFlow core to your application. Pass a single configuration object to register views, feed initial events, toggle optional UI, and connect lifecycle callbacks. This guide breaks down every available option.

Quick Start

import {
  useCalendarApp,
  DayFlowCalendar,
  createMonthView,
  createWeekView,
  ViewType,
} from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import '@dayflow/core/dist/styles.css';

export function TeamCalendar() {
  const calendar = useCalendarApp({
    views: [createMonthView(), createWeekView()],
    defaultView: ViewType.MONTH,
    initialDate: new Date(),
    events: [],
  });

  return <DayFlowCalendar calendar={calendar} />;
}

Configuration Overview

OptionTypeRequiredDefaultDescription
viewsCalendarView[]Required—Registers the view definitions (e.g., createMonthView()). At least one view is required.
pluginsCalendarPlugin[]Optional[]Installs optional plugins (drag helpers, shortcuts, etc.). Each plugin receives the app instance during install.
eventsEvent[]Optional[]Initial event payload. Use addEvent/updateEvent afterward to mutate state.
callbacksCalendarCallbacksOptional{}Lifecycle hooks that fire when views, dates, or events change—perfect for syncing with APIs.
defaultViewViewTypeOptionalViewType.WEEKView that loads first; must exist in views.
initialDateDateOptionalnew Date()Starting focus date (also seeds visible month calculations).
timeZonestringOptionalUser's system timezoneGlobal display and editing timezone for all views.
switcherMode'buttons' | 'select'Optional'buttons'Controls how the built-in view switcher renders in headers.
calendarsCalendarType[]Optional[]Registers calendar categories (Work, Personal, etc.) with colors and visibility.
defaultCalendarstringOptionalFirst visible calendarID used when new events are created.
themeThemeConfigOptional{ mode: 'light' }Sets global theme mode and optional token overrides.
localestring | LocaleOptional'en-US'Sets the locale for internationalization (i18n). Supports language codes (e.g., 'ja') or Locale objects.
useEventDetailDialogbooleanOptionalfalseEnables the default modal detail dialog instead of inline panels.
useCalendarHeaderbooleanOptionaltrueEnables the default header (true) or hides it (false). For a custom header, use the calendarHeader slot on DayFlowCalendar.
readOnlyboolean | ReadOnlyConfigOptionalfalseDisables built-in mutation UI. Can be a boolean or a config for fine-grained control (drag/view). Programmatic event APIs still work.
customMobileEventRendererMobileEventRendererOptional—Custom component to replace the default mobile event drawer/dialog.
allDaySortComparatorAllDaySortComparatorOptionalCalendar-group order with multi-day all-day events firstCustom comparator controlling the row order of all-day events across all views. When provided, it fully overrides the default order.

Key Options

Views (required)

  • Each view is a CalendarView object { type, component, config }.
  • DayFlow ships with factories (createDayView, createWeekView, etc.) that return ready-made definitions.
  • defaultView must match one of the registered view types; otherwise the app throws during initialization.

Events

  • The provided array becomes the in-memory CalendarApp.state.events list.
  • useCalendarApp watches app mutations, so calling calendar.addEvent() or calendar.updateEvent() automatically syncs application state.
  • Make sure events adhere to the Event interface (start/end accept PlainDate, PlainDateTime, or ZonedDateTime).

Plugins

  • A plugin has { name, install(app), config } and is executed once during construction.
  • Use plugins to register drag handlers, keyboard shortcuts, analytics observers, or expose custom APIs via app.getPlugin(name).

Callbacks

callbacks keep state in sync with your backend or analytics layer:

  • onViewChange(view) fires after a successful view switch.
  • onDateChange(date) fires whenever the focused date changes (navigation or selection).
  • onVisibleRangeChange(start, end, reason) fires whenever visible date-range shifts. Helps in more precise fetches without additional calculations.
  • onEventCreate(event), onEventUpdate(event), onEventDelete(id) mirror CRUD operations—ideal for syncing APIs.
  • onEventDoubleClick(event, e) fires when an event is double-clicked. Use e.currentTarget as an anchor for external popovers, and return false to suppress DayFlow's default detail panel/dialog.
  • onMoreEventsClick(date) fires when the "+ X more" link is clicked in Month view.
  • onCalendarCreate(calendar), onCalendarUpdate(calendar), onCalendarDelete(id) mirror calendar CRUD operations.
  • onCalendarMerge(sourceId, targetId) fires when merging two calendars (e.g., merging "Work" into "Personal").
  • onRender() executes when the calendar finishes a render pass (useful for instrumentation).

defaultView & initialDate

  • defaultView sets the initial state.currentView. If omitted, DayFlow falls back to ViewType.WEEK, so explicitly set it for single-view calendars.
  • initialDate seeds both state.currentDate and the internal visibleMonth. Override it if you pull the date from routing or user settings.

timeZone

  • timeZone defines the primary display and editing timezone for Day, Week, Month, and Year views.
  • If omitted, DayFlow resolves it from the user's system timezone.
  • Changing timeZone reprojects the UI, but does not itself mutate event data.
  • Edit callbacks still return canonical event data after the change is applied. DayFlow does not persist the temporary UI projection timezone as the stored event shape.
  • Day/Week secondaryTimeZone remains a display-only reference axis and does not replace the primary app timezone.

switcherMode

  • 'buttons': renders a horizontal button group, great for desktop.
  • 'select': renders a dropdown, perfect when space is limited or you expose many view types.

calendars & defaultCalendar

  • calendars defines each calendar type (id, name, colors, visibility). The Calendar Registry automatically picks light/dark colors based on theme.mode ('light' | 'dark' | 'auto').
  • defaultCalendar determines which calendar new events inherit; if omitted, the first visible calendar wins.

CalendarType properties:

PropertyTypeRequiredDescription
idstringYesUnique identifier (e.g., 'work', 'personal').
namestringYesDisplay name shown in the UI.
colorsCalendarColorsYesLight mode color set (see below).
darkColorsCalendarColorsNoDark mode color set; falls back to colors if omitted.
descriptionstringNoOptional human-readable description.
iconstringNoEmoji or icon name displayed alongside the calendar name.
isVisiblebooleanNoWhether events of this calendar are shown. Defaults to true.
isDefaultbooleanNoMarks this as a system default calendar.
readOnlybooleanNoDisables drag, resize, and edit UI for events in this calendar.
sourcestringNoOrigin label (e.g., 'Google Calendar', 'iCloud').
subscription{ url, status, meta? }NoSubscription metadata for ICS/remote calendars.

CalendarColors properties:

PropertyTypeDescription
eventColorstringEvent background color (usually translucent).
eventSelectedColorstringEvent background when selected.
lineColorstringAccent / border color.
textColorstringEvent text color.

theme

The theme configuration controls the visual appearance of the entire calendar:

const calendar = useCalendarApp({
  theme: {
    mode: 'dark', // 'light' | 'dark' | 'auto'
  },
});

Theme Modes:

  • 'light': Light mode with light backgrounds and dark text (default)
  • 'dark': Dark mode with dark backgrounds and light text
  • 'auto': Automatically follows system theme preference

Programmatic Theme Changes:

// Get current theme
const currentTheme = calendar.app.getTheme();

// Set theme
calendar.app.setTheme('dark');

// Subscribe to theme changes
calendar.app.subscribeThemeChange(theme => {
  console.log('Theme changed to:', theme);
});

Custom Dark Mode Colors:

Define different colors for light and dark modes for each calendar type:

const calendars = [
  {
    id: 'work',
    name: 'Work',
    colors: {
      // Light mode colors
      lineColor: '#0066cc',
      eventColor: '#e6f2ff',
      eventSelectedColor: '#cce4ff',
      textColor: '#003d7a',
    },
    darkColors: {
      // Dark mode colors
      lineColor: '#4da6ff',
      eventColor: '#1a3d5c',
      eventSelectedColor: '#2a5a8a',
      textColor: '#b3d9ff',
    },
  },
];

See Dark Mode for comprehensive theming documentation.

locale

The locale option sets the language and regional settings for the calendar.

  • String: Use a language code like 'en-US', 'ja', 'zh', 'de', 'fr', 'es', 'ko'.
  • Locale Object: Pass an imported Locale object for type safety or a custom object for unsupported languages.
// String code
const calendar = useCalendarApp({
  locale: 'ja',
});

// Built-in Locale object
import { ja } from '@dayflow/core';
const calendar = useCalendarApp({
  locale: ja,
});

// Custom Locale object
const customLocale = {
  code: 'it',
  messages: { today: 'Oggi', ... }
};
const calendar = useCalendarApp({
  locale: customLocale,
});

useEventDetailDialog

  • true turns on the default modal dialog (DefaultEventDetailDialog).
  • Combine with customDetailPanelContent or customEventDetailDialog on DayFlowCalendar to swap the UI while keeping the core state machine.

useCalendarHeader

  • true (default): Renders the built-in calendar header.
  • false: Hides the header entirely.

To render a custom header, use the calendarHeader slot on DayFlowCalendar. See Calendar Header for details.

readOnly

  • true: Disables built-in mutation UI (dragging, creating, editing).
  • ReadOnlyConfig: Fine-grained control.
    • draggable: Whether dragging is allowed.
    • viewable: Whether opening event details is allowed.
  • Programmatic APIs such as calendar.addEvent(), calendar.updateEvent(), calendar.deleteEvent(), and calendar.applyEventsChanges() still work in read-only mode.
  • Use calendar.canMutateFromUI() in custom UI to decide whether create/edit/delete controls should be shown.
  • See Read-only Mode for details.

customMobileEventRenderer

  • Allows replacing the default bottom-drawer for mobile event editing with your own component.
  • See Sidebar Plugin for more on specific features.

allDaySortComparator

Controls the row order of all-day events in every view (day, week, month, year).

By default, DayFlow:

  • groups all-day events by calendarId in first-seen order
  • keeps multi-day all-day events above single-day all-day events
  • keeps same-calendar all-day events visually grouped together

Pass allDaySortComparator only when you want to take full control of the final order. Once provided, the comparator result is used directly.

Pass a comparator to take full control — it receives two Event objects and works like JavaScript's Array.sort:

const calendar = useCalendarApp({
  allDaySortComparator: (a, b) => a.title.localeCompare(b.title),
});

Available exported helper from @dayflow/core:

HelperBehavior
sortAllDayByTitleSorts all-day events alphabetically by title and fully overrides the default grouping flow
import { sortAllDayByTitle } from '@dayflow/core';

const calendar = useCalendarApp({
  allDaySortComparator: sortAllDayByTitle,
});

Use updateConfig to change the sort at runtime:

calendar.app.updateConfig({ allDaySortComparator: sortAllDayByTitle });

// Restore the default calendar-grouped ordering
calendar.app.updateConfig({ allDaySortComparator: undefined });

Advanced Configuration Example

import {
  useCalendarApp,
  DayFlowCalendar,
  createMonthView,
  createWeekView,
  ViewType,
} from '@dayflow/react'; // or '@dayflow/vue', '@dayflow/svelte', '@dayflow/angular'
import { createSidebarPlugin } from '@dayflow/plugin-sidebar';
import '@dayflow/core/dist/styles.css';

const calendars = [
  {
    id: 'work',
    name: 'Work',
    colors: {
      eventColor: '#2563eb',
      eventSelectedColor: '#1d4ed8',
      lineColor: '#1e40af',
      textColor: '#ffffff',
    },
  },
  {
    id: 'personal',
    name: 'Personal',
    colors: {
      eventColor: '#f97316',
      eventSelectedColor: '#ea580c',
      lineColor: '#c2410c',
      textColor: '#ffffff',
    },
  },
];

export function AdvancedCalendar() {
  const calendar = useCalendarApp({
    views: [createMonthView(), createWeekView()],
    defaultView: ViewType.WEEK,
    initialDate: new Date('2024-10-01'),
    events: [],
    calendars,
    defaultCalendar: 'work',
    switcherMode: 'select',
    callbacks: {
      onEventUpdate: event => api.events.update(event),
      onVisibleRangeChange: (start, end, reason) =>
        preloadVisibleRange(start, end, reason),
    },
    plugins: [
      createSidebarPlugin({
        width: 280,
        initialCollapsed: false,
      }),
    ],
    useEventDetailDialog: true,
  });

  return <DayFlowCalendar calendar={calendar} />;
}

Tip: The object returned by useCalendarApp exposes both state (currentView, currentDate, events) and actions. Share the same instance with DayFlowCalendar, your own toolbar, and side panels to keep everything synchronized.

On this page