Event Overlap

Lists what a new or moved calendar event runs into and moves it to the nearest free slot, so meetings aren't booked on top of each other.

StopsMeeting booked on top of another

Installation

pnpm dlx shadcn@latest add https://bollard-ui.vercel.app/r/event-overlap.json

The files land in your project. They're yours to edit.

Usage

event-overlap-usage.tsx
import { EventOverlap, type CalendarEvent } from "@/components/ui/event-overlap"

<EventOverlap
  draft={draft}
  events={events}
  timeZone="Asia/Kolkata"
  travelMinutes={travel}
  now={NOW}
  onMove={(start, end) => setDraft((d) => ({ ...d, start: start.getTime(), end: end.getTime() }))}
/>

What it catches

  • Overlapping events and busy all-day events
  • Back-to-back events with no break
  • Too little travel time between places
  • Events in other time zones, shown in their own local time
  • The nearest free slot within work hours, with Undo

Props

EventOverlap props
PropTypeDefault
draft* (required)

The event being created or moved.

DraftEvent—
events* (required)

Events already on the calendar.

CalendarEvent[]—
workHours

Working hours [start, end) in your zone, for the suggested slot.

[number, number][9, 18]
step

Granularity of suggested starts, in minutes.

number15
now

"Now", so no slot in the past is offered. Pass it for deterministic previews.

Date | number—
onMove

Move the draft. Called with the suggested slot, and with the old times on Undo.

(start: Date, end: Date) => void—
reasons

Reason templates per kind: `{minutes}`, `{needed}`, `{gap}` and `{route}` are filled in.

Partial<Record<ConflictKind, string>>—
conflictText

Templates: `{count}` and `{time}` are filled in.

string"Clashes with {count}"
clearText

Shown when there are no clashes.

string"No clashes. Your buffer and travel time are kept."
moveLabel

Text for the move-to-free-slot button.

string"Move to {time}"
undoLabel

Text for the Undo button.

string"Undo"
noSlotText

Shown when no free slot is found.

string"No free slot of this length in the next week."
localTimeText

Text giving another zone's local time.

string"{time} {zone} where it happens"
locale

Locale for times and dates.

string"en-GB"
hour12

12-hour clock (2:30 PM). Set false for 14:30.

booleantrue
labels

Override any other string.

Partial<typeof EVENT_OVERLAP_LABELS>—

* required. Also accepts the native props of <div> (className, aria-*, data-*…), passed through to it.

Accessibility

  • The timeline is aria-hidden; clashes are listed in text
  • Results are aria-live="polite"
  • Move and Undo are buttons with visible text

Only what the source does. Test with your own screen reader and content before shipping.

Limitations

  • Only knows the events you pass; other calendars are unseen
  • Travel times come from your data

What it stops

Meeting booked on top of another

Also known as

calendar · double booking · conflict · meeting scheduler · calendly · buffer time · travel time · time zone

Field type

Dependencies

Pairs well with