Building a Pseudo-Infinite Calendar

Ashish Khare

September 23, 2025

Banner for Building a Pseudo-Infinite Calendar

Let’s start with what we’re going to build. The challenge is to create a pseudo-infinite calendar where you can view daily recorded journals. We'll focus strictly on implementing the calendar.

Demo: Infinite Calendar

Requirements

Here are some requirements for a buttery-smooth UI:

  1. Implement infinite past/future scroll
  2. Ensure continuous scroll — no snap-to-month behavior
  3. Support partial visibility of two months in the viewport
  4. Load new months seamlessly without flicker or jumps
  5. Virtualize rows (weeks) to reduce DOM nodes
  6. Compute week rows on the fly
  7. Optimize images with lazy loading

For this task, I experimented with virtual lists and on-demand week data generation. The image below illustrates the trick I used to render (pseudo-)infinite months in the calendar. I broke the approach into two parts — let’s go through both.

Illustration explaining the calendar loadout

Only the Future

First, I tackled generating future months. This can be done by adding subsequent weeks to the current week. The date-fns library was especially helpful in handling edge cases for calendar dates. For example:

md
Current Week + 1 Week = Next Week  
Current Week + 2 Weeks = Second Week in the Future  
...  

Broadly,  
Current Week + n Weeks = nth Week in the Future

Since the calendar is continuous, we don’t need to worry about month padding. We only need to calculate the requested week.

I used the react-virtuoso feature that provides the index of the row being rendered on the screen. This index directly maps to the required week, making it possible to render (almost) infinite months into the future.

The Past Too

Rendering past months was more challenging. I thought about binary search and figured: why not start in the middle and expand in both directions?

By splitting rows into two parts, the upper section represents past weeks and the lower section represents future weeks, with the current week in the middle (see the image). The previous technique can then be reused to calculate weeks.

md
Middle Row – Row Index = Offset  

If Offset > 0 → Current Week – Offset Weeks = Past Week  
If Offset = 0 → Current Week  
If Offset < 0 → Current Week + |Offset| Weeks = Future Week

However, react-virtuoso indexes rows from zero to the total count, so I set the middle (total_row_count / 2) as the starting point, scrolled to it initially, and computed weeks relative to that point. The offset is simply (middle - row_index). Its sign tells us whether to add weeks (future) or subtract weeks (past).

Code

Here’s the main table logic for rendering weeks. The rangeChanged function calculates the midpoint of the rendered range, which determines the active month. I also reduced the overscan property to render only two rows outside the viewport for efficiency.

In addition, the offset from the midpoint determines the start date of the currently visible week. If the offset is negative, you subtract weeks; otherwise, you add them.

tsx
// CalendarTable

const TOTAL_WEEKS = 100_000;
const START_INDEX = TOTAL_WEEKS / 2;

const [activeRangeMid, setActiveRangeMid] = useState(START_INDEX);
const [currentItemIndex, setCurrentItemIndex] = useState(-1);

function getWeekStartDate(index: number, startIndex: number): Date {
  const baseWeekStart = startOfWeek(new Date());
  const offset = index - startIndex;
  return offset >= 0
    ? addWeeks(baseWeekStart, offset)
    : subWeeks(baseWeekStart, -offset);
}

<Virtuoso
  totalCount={TOTAL_WEEKS}
  initialTopMostItemIndex={START_INDEX - 1}
  overscan={2}
  increaseViewportBy={200}
  context={{ currentItemIndex, isScrolling }}
  rangeChanged={({ endIndex, startIndex }) =>
    setActiveRangeMid(Math.round((endIndex + startIndex) / 2))
  }
/>

The rendering logic for each week is straightforward. Calculate the start of the week, then create an array of seven days. Each day object includes properties such as isCurrentMonth and isToday. Finally, render them in a grid.

tsx
// CalendarRow

const weekStart = getWeekStartDate(activeRangeMid, START_INDEX);
const days: Day[] = Array.from({ length: 7 }, (_, i) => {
  const date = addDays(weekStart, i);
  return {
    date: format(date, "dd/MM/yyyy"),
    day: format(date, "d"),
    isCurrentMonth: getMonth(date) === activeMonth,
    isToday: isToday(date),
  };
});

<div className="relative">
  <div className="relative grid grid-cols-7 gap-px">
    {days.map((day) => (
      <CalendarCell key={day.date} {...day} />
    ))}
  </div>
</div>

Conclusion

This approach of computing weeks based on the row index is why I call it a pseudo-infinite calendar. True infinity only exists in mathematics.

To improve efficiency further, the calendar could be implemented in pure JavaScript without relying on a virtual list. This would involve calculating weeks dynamically based on scroll offset from the center, while maintaining an overscan buffer and tracking the number of rendered rows. This way, you can determine the active month—that is, the month that occupies most of the viewport.

By combining dynamic week rendering with virtualization, you can implement a smooth, responsive calendar UI.