Quick Answer: Calendar app design is mostly about state, date math, and layout edge cases, not visuals. The open-source kargulstudio/calender-app-design repo shows a working approach: a Next.js 16 front end, Zustand state persisted to localStorage, working-day calculations that skip weekends and holidays, and a calendar grid that handles overlapping events. It has no backend, which makes it a strong learning reference and a poor production template.

Most calendar mockups look finished in Figma and fall apart the first time someone drags an event across midnight or requests leave over a public holiday. That gap is where calendar app design actually lives. The Kargul Workspace prototype, built from a "Dashboard – calendar" Figma file, reproduces its Time off page pixel for pixel and then builds the behavior around it. Here's what it gets right, what it skips, and what you should copy if you're building something similar.

Why a working prototype beats a static mockup

A Figma file can show a request dialog with a balance of seven days. It can't tell you what happens when someone requests five days across a holiday and the number changes. Working prototypes expose those questions early.

The repo runs entirely in the browser. There's no API and no database, and every change is saved to localStorage. That sounds like a limitation, and it is. It's also what makes the prototype useful: you can test drag-to-create, resize, and balance logic without waiting on a backend team. Most guides tell you to build the API first. For UX validation, that advice is backwards, because you learn more from a clickable app with fake data than from a schema nobody has used.

Building the calendar grid: drag, resize, and overlap

The calendar supports week, day, and month views. You drag on empty space to create an event, drag an event to move it across days, and drag its bottom edge to resize. Overlapping events lay out side by side, and an all-day lane shows public holidays. A live now-line keeps the current time visible.

The hard part is overlap. When two events share time, the layout has to assign columns so neither event hides the other. A common approach is to sort events by start time, group those that touch each other into clusters, and then assign each event the first column free within its cluster. Once you have clusters, the rendering is simple. Without them, every overlap bug looks like a random visual glitch.

Here's where most teams underestimate the work: drag and resize must snap to the same grid the layout uses. If the drag snaps to 15 minutes but the render rounds to 30, events jump on release. Pick one grid unit at the start and enforce it everywhere.

Working-day math is where leave tools break

The request dialog counts working days and skips weekends and holidays. This is the feature that decides whether a time-off tool earns trust.

Take the seed data. The prototype is set to the week of November 8–14, 2026, with Tuesday November 10 selected. If someone requests Monday November 9 through Friday November 13, the correct count is five working days, assuming no holidays fall in that range. A naive end - start in days returns four, because it misses the inclusive endpoint. Off-by-one errors like this are the first thing employees notice and the last thing developers test.

The fix is to iterate day by day, check each date against a weekend rule and a holiday set, and count only the valid ones. It's slower than arithmetic, but a leave range is at most a few hundred days, so performance isn't a concern. Correctness is.

Here's the part practitioners don't advertise: holiday data is region-specific and changes every year. Hard-code one country's holidays and your tool quietly miscounts for everyone else. Treat the holiday list as configuration, not logic.

Persisting state with Zustand and localStorage

The app uses Zustand with the persist middleware, which writes state to localStorage. The Settings page includes a "Reset demo data" action, which is a useful pattern: any prototype with persisted state needs a reliable way back to a known starting point.

Compare the storage options before you copy this approach:

Storage optionScopeShared across usersBest fit
localStorageSingle browser, single origin, synchronous string valuesNoPrototypes, demo state, small preferences
IndexedDBSingle browser, async, structured data with much larger quotasNoOffline-first apps and larger local datasets
Server database (e.g., PostgreSQL)Central serverYesMulti-user leave approval and real records

The prototype is clearly in the first row. That's fine for a design review. It is not fine for a leave system, because a manager's approval exists only in the manager's browser.

The caveat: localStorage is synchronous and blocks the main thread on large writes, so keep the persisted state small. Store the data you need to restore a view, not every computed value.

Keyboard shortcuts and the command palette

Keyboard support is one of the cheapest ways to make a calendar feel professional. The prototype maps N to a new event, R to a time-off request, T to today, arrow keys to move between periods, and D, W, and M to switch views. ⌘K opens a command palette built with cmdk, which searches pages, events, requests, documents, and invoices.

This matters more than it looks. Power users of calendar tools rarely click through menus. If the shortcut layer is missing, they'll stop using the tool within a week. Build shortcuts early, and make sure they don't fire while a user is typing in an input field. That single check prevents the most common complaint about keyboard shortcuts.

Most people treat shortcuts as a polish item. I'd argue they're part of the core interaction model, and they belong in the first sprint.

Where this prototype stops

The README is honest about scope, and you should be too when you evaluate it. The prototype:

  • Has no authentication, so there's no real identity behind "manager approve" actions.
  • Stores everything per browser, so two people never see the same calendar.
  • Ships seed data designed to match the Figma screens, not realistic usage volumes.
  • Doesn't include a tested leave policy engine for accrual, carry-over, or regional rules.

These gaps are the actual product work. The UI is a head start, not a finished leave system. If you plan to ship something similar, the next steps are a server-side source of truth, role-based permissions, and an audit trail for every approval and edit.

A useful test: if your tool can't answer "who approved this request, and when?" it isn't ready for real employees, no matter how good the grid looks.

Frequently Asked Questions

What is calendar app design?

Calendar app design is the work of building the interface and behavior of a scheduling tool. It covers the visual layout, but also drag-and-drop interactions, overlapping event layout, date arithmetic, time zones, and keyboard navigation. Good calendar app design treats those behaviors as the core, since they decide whether users trust the tool. Visual polish matters, but it comes second.

How do you build a calendar app with Next.js?

Start with the routes, then build a time grid component that maps time to pixels with one fixed unit, such as 15 minutes. Add a state store, like Zustand with persistence, for events and requests. Next, implement overlap layout by clustering events and assigning columns. Test drag, resize, and working-day counts before adding any styling. The Kargul prototype follows this order.

Why does a time-off calendar count working days wrong?

The usual cause is an inclusive-range bug. A date difference counts the gaps between dates, so a Monday-to-Friday request appears as four days instead of five. Holidays and weekend rules add more errors if they're hard-coded. Iterate each date in the range, skip non-working days using a region-specific holiday list, and test ranges that cross month boundaries.

Can you use localStorage for a real calendar app?

Only for single-user tools or prototypes. localStorage stays in one browser, so it can't share events or approvals across a team. It also has limited capacity and is synchronous, so large writes can slow the page. For a multi-user product, move the source of truth to a server database and use local storage only as a cache.

Is the kargulstudio calendar app production-ready?

No. The repo is a design prototype with no backend, no authentication, and per-browser data. Its value is in the interaction patterns and the seed-driven design, which you can study and adapt. Treat it as a reference implementation for the front end, and build the server, permissions, and audit logging yourself.

Start with one test you can run today

Clone the repo, run npm install and npm run dev, then request five working days across a week and check the balance. Next, drag an event over another one and see how the layout responds. Note every place where the behavior surprised you. Those surprises are your real calendar app design brief, and they'll tell you more than any mockup. Pass this to a teammate who's wrestling with overlapping events or leave math, and compare notes.