1.0

The open-source calendar for booking apps.

Week, day, month and list views for React 19 and shadcn/ui. Drag, resize, time zones, recurrence. MIT, no premium tier.

Try it: drag a booking, pull its edge, or select a free time. Space and the arrow keys work too.

Built for booking, not just for showing dates.

Bookings come with rules, time zones and a server behind them. The calendar treats all three as its own concern, so your app passes data and answers callbacks.

Bookings from the Hapio API, in three callbacks.

Hapio is the booking and scheduling API: services, resources, schedules and bookable slots live there. Your server talks to it with the hapio-sdk package and the calendar talks to your server, so your API token never reaches the browser.

  • Load

    An event source fetches each visible range. Your route calls getBookings with starts_at bounds and returns plain JSON.

  • Book

    Show getServiceBookableSlots as open time and let customers select inside it. The selection becomes a postBooking.

  • Reschedule

    A drag or a keyboard move calls onEventChange. The booking shows at its new time while your server saves it, and reverts if Hapio refuses.

Hapio Calendar is made by Hapio, the team behind the API. The guides: Events and data and Moving and resizing events.

components/bookings-calendar.tsx
// Your server keeps the token: app/api/bookings/route.ts answers with
//   hapio.getBookings({ query: { 'starts_at[gte]': from, 'starts_at[lte]': to } })
// where hapio = createHapioClient({ token: process.env.HAPIO_TOKEN }).
const SOURCES: EventSource<CalendarEventInput<HapioBooking>>[] = [
  {
    id: 'hapio',
    window: 'week', // whole weeks: moving inside a loaded week fetches nothing
    async fetch(range, { signal }) {
      const url = `/api/bookings?from=${range.startIso}&to=${range.endIso}`
      const response = await fetch(url, { signal })
      const bookings: HapioBooking[] = await response.json()
      return bookings.map((booking) => ({
        id: booking.id,
        title: booking.metadata.customer,
        start: booking.starts_at,
        end: booking.ends_at,
        resourceId: booking.resource_id,
        data: booking,
      }))
    },
  },
]

export function BookingsCalendar() {
  return (
    <CalendarEditing>
      <HapioCalendar
        eventSources={SOURCES}
        timeZone="Europe/Stockholm"
        editable
        onEventChange={(change) => reschedule(change.event.id, change.next)}
        selectable
        onSelect={({ span }) => book(span)}
        className="h-[36rem]"
      />
    </CalendarEditing>
  )
}

Add it to your shadcn/ui app.

  1. Add the registry namespace

    The registry items name each other @hapio/<item>; the namespace in components.json resolves them.

    components.json
    {
      "registries": {
        "@hapio": "https://calendar.hapio.io/r/{style}/{name}.json"
      }
    }
    
  2. Add the block

    The shadcn CLI copies the files into components/hapio-calendar/, adds the shadcn components they use and installs @hapio/calendar-react and the Temporal polyfill.

    npx shadcn@latest add @hapio/hapio-calendar
    
  3. Render it

    Events, a time zone and a height. The toolbar, the four views and the keyboard come with the block.

    <HapioCalendar events={events} timeZone="Europe/Stockholm" className="h-[36rem]" />
    

The installation guide has the full steps.

Three layers. You choose the depth.

Most apps use the block and its props. When the props are not enough, edit the copied files; when you need markup of your own, build it on the hooks.

  • @hapio/calendar-core

    Framework-free TypeScript: dates, time zones, layout, rules, the interaction engines and the store. Safe to import in React Server Components.

  • @hapio/calendar-react

    Hooks that return prop-getters with every role, ARIA attribute, id, handler and geometry variable an element needs. No DOM, no CSS.

  • @hapio registry

    The styled components, HapioCalendar included. The shadcn CLI copies them into your app, so every element and Tailwind class is yours to edit.

Read the docs

Free, all of it.

MIT licensed, every view and feature, now and later. Resource timelines, virtualization and print are planned as free features too.

Migrating from another calendar? Change one import.