Hooks
All hooks must be used inside a <CalendarProvider> component. If you’re using the <Calendar> component, the provider is already set up for you.
useCalendar()
Section titled “useCalendar()”Main orchestrator — combines state, events, and navigation.
import { useCalendar } from "trud-calendar";
const { currentDate, // DateString — current focused date view, // CalendarView — current view events, // CalendarEvent[] — all events visibleEvents, // CalendarEvent[] — filtered to visible range visibleRange, // { start: DateString, end: DateString } locale, // string — BCP 47 locale prev, // () => void — go to previous period next, // () => void — go to next period today, // () => void — go to today setDate, // (date: DateString) => void setView, // (view: CalendarView) => void} = useCalendar();useNavigation()
Section titled “useNavigation()”Date navigation and view switching. Lighter than useCalendar — use this when you only need nav controls.
import { useNavigation } from "trud-calendar";
const { currentDate, // DateString view, // CalendarView formattedDate, // string — locale-aware title (e.g., "March 2026") prev, // () => void next, // () => void today, // () => void setDate, // (date: DateString) => void setView, // (view: CalendarView) => void} = useNavigation();useEvents()
Section titled “useEvents()”Access event data for the current visible range.
import { useEvents } from "trud-calendar";
const { visibleEvents, // CalendarEvent[] — sorted, filtered to visible range getForDay, // (date: DateString) => CalendarEvent[] partitioned, // { allDay: CalendarEvent[], timed: CalendarEvent[] } segments, // EventSegment[] — multi-day event segments groupedByDate, // Map<DateString, CalendarEvent[]>} = useEvents();Example: Get events for a specific day
Section titled “Example: Get events for a specific day”const { getForDay } = useEvents();const todayEvents = getForDay("2026-03-13");useEventLayout(events)
Section titled “useEventLayout(events)”Column-packing algorithm for overlapping events. Used internally by the week/day time grid — call it yourself when building custom time-based layouts.
import { useEventLayout } from "trud-calendar";
const positioned: PositionedEvent[] = useEventLayout(timedEvents);Each PositionedEvent contains:
interface PositionedEvent { event: CalendarEvent; column: number; // 0-based column index in overlap group totalColumns: number; // Total columns in overlap group top: number; // % from top (0-100) height: number; // % height (0-100)}Use these values to position events with CSS:
{positioned.map(({ event, column, totalColumns, top, height }) => ( <div key={event.id} style={{ position: "absolute", top: `${top}%`, height: `${height}%`, left: `${(column / totalColumns) * 100}%`, width: `${100 / totalColumns}%`, }} > {event.title} </div>))}useCurrentTime(intervalMs?)
Section titled “useCurrentTime(intervalMs?)”Live clock for “current time” indicators. Updates every 60 seconds by default.
import { useCurrentTime } from "trud-calendar";
const { now, // string — ISO datetime of current moment today, // string — YYYY-MM-DD of today timeOfDay, // number — fractional hour (14.5 = 2:30 PM)} = useCurrentTime();
// Custom interval: update every 10 secondsconst time = useCurrentTime(10_000);Example: Current time indicator
Section titled “Example: Current time indicator”const { timeOfDay } = useCurrentTime();const topPercent = ((timeOfDay - dayStartHour) / (dayEndHour - dayStartHour)) * 100;
<div className="absolute left-0 right-0 border-t-2 border-red-500 z-10" style={{ top: `${topPercent}%` }}/>useDateFormat()
Section titled “useDateFormat()”Locale-aware date formatting functions powered by the Intl API.
import { useDateFormat } from "trud-calendar";
const fmt = useDateFormat();
fmt.toolbarTitle("2026-03-13", "month"); // "March 2026"fmt.toolbarTitle("2026-03-13", "week"); // "Mar 9 – 15, 2026"fmt.time("2026-03-13T14:30:00"); // "2:30 PM"fmt.timeRange(start, end); // "2:30 – 3:00 PM"fmt.weekdayShort("2026-03-13"); // "Fri"fmt.weekdayNarrow("2026-03-13"); // "F"fmt.dayNumber("2026-03-13"); // "13"fmt.agendaDate("2026-03-13"); // "Friday, March 13"fmt.monthDay("2026-03-13"); // "Mar 13"All functions respect the locale set in the CalendarProvider.
useEventDrag()
Section titled “useEventDrag()”Pointer-based event drag hook for building custom drag interactions. Used internally by WeekView and MonthView.
import { useEventDrag } from "trud-calendar";
const { dragState, // DragState | null — current drag state onPointerDown, // (e: React.PointerEvent, event: CalendarEvent) => void isDragging, // boolean didDrag, // React.RefObject<boolean> — true if a drag occurred (suppress click)} = useEventDrag({ mode: "time", // "time" for week/day, "date" for month onEventDrop, // (event, newStart, newEnd) => void enabled: true, // boolean snapDuration: 15, // snap increment in minutes dragConstraint, // (event, newStart, newEnd) => boolean — optional});DragState contains:
event— the event being draggedghostX,ghostY— cursor position for rendering a drag ghosttargetDay— the day column the cursor is over (detected viadata-dayattributes)
Supports both mouse and touch interactions via Pointer Events API.
useAutoScroll()
Section titled “useAutoScroll()”Auto-scrolls a container when the pointer approaches its top or bottom edge. Integrated into the week/day view during drag, resize, and slot selection — you only need this hook when building custom scrollable layouts.
import { useAutoScroll } from "trud-calendar";
const { handleAutoScroll, stopAutoScroll } = useAutoScroll({ containerRef: scrollRef, // React.RefObject<HTMLElement> enabled: isDragging, // activate only during interactions});
// Call on every pointermove:handleAutoScroll(e.clientY);
// Call on pointerup:stopAutoScroll();useGridKeyboard()
Section titled “useGridKeyboard()”Keyboard navigation hook implementing the WAI-ARIA roving tabindex grid pattern.
import { useGridKeyboard } from "trud-calendar";
const grid = useGridKeyboard({ cols: 7, rows: 24, onActivate: (row, col) => { /* Enter/Space pressed */ }, onEscape: () => { /* Escape pressed */ },});Returns:
registerCell(row, col)— ref callback for grid cellsgetTabIndex(row, col)— returns0for the active cell,-1for othershandleKeyDown— keyboard event handlerhandleFocus(row, col)— focus event handler
useUndoableEvents()
Section titled “useUndoableEvents()”Wraps a CalendarEvent[] with a full undo/redo stack. Auto-snapshots before onEventDrop and onEventResize apply, and registers Ctrl+Z / Ctrl+Shift+Z (Ctrl+Y) keyboard shortcuts.
import { useUndoableEvents } from "trud-calendar";
const { events, // CalendarEvent[] — current state setEvents, // (events: CalendarEvent[]) => void — update + auto-snapshot onEventDrop, // (event, newStart, newEnd) => void — snapshots before applying onEventResize, // (event, newStart, newEnd) => void — snapshots before applying undo, // () => void redo, // () => void canUndo, // boolean canRedo, // boolean snapshot, // () => void — manual snapshot (e.g., before a batch update)} = useUndoableEvents({ initialEvents: myEvents, maxHistory: 30, // optional, defaults to 30});Example: Calendar with undo/redo
Section titled “Example: Calendar with undo/redo”function App() { const undoable = useUndoableEvents({ initialEvents: myEvents });
return ( <> <div className="flex gap-2 mb-2"> <button onClick={undoable.undo} disabled={!undoable.canUndo}>Undo</button> <button onClick={undoable.redo} disabled={!undoable.canRedo}>Redo</button> </div> <Calendar events={undoable.events} enableDnD onEventDrop={undoable.onEventDrop} onEventResize={undoable.onEventResize} /> </> );}useEventSelection()
Section titled “useEventSelection()”Multi-select event management with Set-based tracking. Supports toggle (Ctrl+click), range select (Shift+click), select all, and clear.
import { useEventSelection } from "trud-calendar";
const { selectedIds, // Set<string> — currently selected event IDs isSelected, // (id: string) => boolean select, // (id: string) => void — single select (clears others) toggle, // (id: string) => void — Ctrl+click behavior rangeSelect, // (id: string, sortedIds: string[]) => void — Shift+click clearSelection, // () => void selectAll, // (ids: string[]) => void lastSelectedId, // string | null — anchor for range selection} = useEventSelection();The <Calendar> component uses SelectionProvider internally, which wraps useEventSelection with modifier key detection. Selected events show a visual ring highlight.
useResponsiveView()
Section titled “useResponsiveView()”Adaptive layout hook using ResizeObserver. Returns breakpoint flags and the recommended number of visible day columns.
import { useResponsiveView } from "trud-calendar";
const ref = useRef<HTMLDivElement>(null);const { isMobile, // boolean — container < 640px isTablet, // boolean — container 640px–1024px containerWidth, // number — measured width in px visibleDays, // 1 (mobile) | 3 (tablet) | 7 (desktop)} = useResponsiveView(ref);The <Calendar> component uses this internally to adapt the week view column count and month view cell sizes.
useSwipeNavigation()
Section titled “useSwipeNavigation()”Touch swipe detection for prev/next navigation. Only activates for pointerType === "touch" — mouse drags are ignored.
import { useSwipeNavigation } from "trud-calendar";
const swipe = useSwipeNavigation({ onSwipeLeft: () => next(), // navigate forward onSwipeRight: () => prev(), // navigate backward threshold: 50, // min horizontal px (default: 50) maxVertical: 30, // max vertical px (default: 30)});
// Spread on the container element:<div onPointerDown={swipe.onPointerDown} onPointerMove={swipe.onPointerMove} onPointerUp={swipe.onPointerUp}> {/* calendar content */}</div>useVirtualScroll()
Section titled “useVirtualScroll()”Viewport-based scroll tracking for filtering visible events. Useful for large datasets where rendering all events is expensive.
import { useVirtualScroll } from "trud-calendar";
const { viewportTop, // number — top edge as % (0–100) viewportBottom, // number — bottom edge as % (0–100) isVirtualized, // boolean — true when enabled} = useVirtualScroll({ containerRef: scrollRef, totalHours: 24, enabled: true, // default: false overscanHours: 2, // extra hours to render above/below viewport});Pair with filterVisibleEvents() from trud-calendar-core to cull off-screen events:
import { filterVisibleEvents } from "trud-calendar-core";
const visible = filterVisibleEvents(positioned, viewportTop, viewportBottom);useEventSources()
Section titled “useEventSources()”Fetches events from one or more sources based on the visible date range. Caches results per range and deduplicates requests.
import { useEventSources, useCalendar } from "trud-calendar";
const { visibleRange } = useCalendar();
const { events, isLoading, refetch } = useEventSources({ sources: [ { url: "/api/events" }, { fetcher: async (start, end) => { const res = await fetch(`/api/team-events?from=${start}&to=${end}`); return res.json(); }}, ], start: visibleRange.start, end: visibleRange.end,});
// Pass to Calendar<Calendar events={events} />Each source can be a url (query params start and end are appended automatically) or a fetcher function. Results from all sources are merged into a single array.
Returns:
events— merged events from all sourcesisLoading— true while any source is fetchingrefetch()— clears the cache and re-fetches all sources
useExternalDrag()
Section titled “useExternalDrag()”Enables dragging items from outside the calendar onto time slots. Uses the native HTML5 Drag and Drop API.
import { useExternalDrag } from "trud-calendar";
const { makeDraggable, dropTargetProps } = useExternalDrag({ onExternalDrop: (info) => { console.log(info.day); // "2026-03-25" console.log(info.start); // "2026-03-25T10:00:00" console.log(info.resourceId); // "room-a" (if resource view) console.log(info.data); // { taskId: "123", title: "My Task" } }, dayStartHour: 8, dayEndHour: 20, snapDuration: 15,});
// Make sidebar items draggable<div {...makeDraggable({ taskId: "123", title: "My Task" })}> Drag me to calendar</div>
// Wrap calendar to accept drops<div {...dropTargetProps}> <Calendar events={events} /></div>ExternalDropInfo contains:
day— the target datestart— snapped start timeresourceId— resource ID if dropped on a resource columndata— the data object you attached viamakeDraggable