04core concepts
Events
CalEvent: the discriminated union on allDay, real instants, colors, attendees, and every optional field.
A CalEvent is a discriminated union on allDay. Timed events carry
offset-qualified instants; all-day events carry date-only instants with an
exclusive end — the RFC 5545 conventions, so events round-trip to real
calendars without translation.
The two shapes
import type { CalEvent } from "@/components/kloq";
const events: CalEvent[] = [
{
id: "1",
title: "Deep work",
start: "2026-08-05T10:00:00+01:00", // offset-qualified instant
end: "2026-08-05T11:30:00+01:00",
color: "blue",
},
{
id: "2",
title: "OOO — Croatia",
allDay: true,
start: "2026-08-06", // date-only instant
end: "2026-08-08", // EXCLUSIVE: covers the 6th and 7th
},
];The union means the compiler enforces the difference: a timed event cannot
carry date-only strings, and an all-day event cannot carry clock times. end
on an all-day event is exclusive — the same convention RFC 5545 uses for a
date-only DTEND — so a one-day event ends on the next date.
Color is optional on purpose
color is one of five palette keys —
"blue" | "violet" | "emerald" | "amber" | "rose" — and an event with no
color of its own takes its calendar's (resolveEventColor). An event that
names a color keeps it wherever it moves. That absence-means-inherit rule is
how a source calendar's color tints everything nobody colored by hand;
DEFAULT_EVENT_COLOR is what an event with neither is drawn in.
Every optional field
description?stringFree text, shown in the event panel.
location?stringA room, an address, "Zoom".
meetingUrl?stringVideo-call link; rendered as a Join affordance.
attendees?Attendee[]Invitees in insertion order; email is the dedupe key. Helpers: addAttendee, removeAttendee, summarize, initialsFor.
organizer?stringRFC 5545 ORGANIZER as a bare address — its own field, never inferred from the attendee list.
reminders?Reminder[]Alerts as offsets from the start. kloq stores them; delivery is the host's job.
busy?booleanFree/busy. Absent means busy — isBusy encodes that default.
readOnly?booleanThe event can't be edited, moved, resized or deleted from the UI.
calendarId?stringThe source calendar the event belongs to.
rrule?stringRFC 5545 RRULE value without the prefix — see the recurrence page.
timeZone?stringThe zone the event was authored in — see the time-zones page.
Attendees and RSVP
Pass currentUserEmail on <Kloq> and the event panel grows an RSVP control
whenever that address is actually on the invite; conflict detection starts
answering "does this clash for me" instead of "do these two overlap"; and
showDeclinedEvents={false} filters events you have declined out of every
surface — still in the store, still findable in ⌘K search, just not on your
calendar.
<Kloq
currentUserEmail="ada@example.com"
showDeclinedEvents={false}
/>CalEvent vs PlacedEvent
Slots never receive a raw CalEvent — they receive a PlacedEvent: the
event projected into the current view's column/minute space, carrying a
branded PlacementId. For a recurring event the two differ (one stored
master, many placed instances); masterIdOf is the bridge back to the store
id. Segment predicates continuesBefore / continuesAfter tell a custom
block to square off the cut edge of a cross-midnight event.