Skip to content
Product block

Month Calendar Grid

A month view where event chips truncate and overflow becomes "+n more", so a busy Tuesday never changes the height of the row it sits in.

191 lineslucide-reactAdded 13 Aug 2026Updated 10 Sept 2026
  • calendar
  • month
  • events
  • schedule
  • grid

What's included

  • components/calendar-month.tsx
  • Needs lucide-react

Works with

  • React
  • Next.js
  • Tailwind CSS
  • TypeScript

npx hoverlab add calendar-month

Or over MCP, from your editor's agent — no account needed.

License

Free to read, copy and install, for personal and non-commercial projects. Shipping it in client work or a paid product needs Pro ($79 once). The source lands in your repo and stops being ours — no attribution, nothing to upgrade.

Was this useful?

Start a page with this section — add more, order them, and leave with the page source.

Preview

August 2026

  • Product
  • Design
  • Personal
MonTueWedThuFriSatSun

Rendered live in your current theme — this is the same component whose source is below, not a screenshot of it.

Source

components/calendar-month.tsx
/**
 * <CalendarMonth> — a month grid for August 2026.
 *
 * A month view's job is density without noise. Event chips truncate to a
 * single line and never wrap, so every week keeps the same row height;
 * when a day holds more than the cell can carry, the overflow collapses
 * to "+2 more" instead of stretching one row and knocking the whole
 * month out of rhythm. Out-of-month days render muted but present —
 * hiding them would break the weekday columns. Colour marks which
 * calendar an event belongs to, and the legend above the grid states
 * that mapping instead of leaving it to be guessed.
 */

import * as React from 'react'
import { ChevronLeft, ChevronRight } from 'lucide-react'

export type CalendarId = 'product' | 'design' | 'personal'

export interface CalendarEvent {
  label: string
  calendar: CalendarId
}

export interface CalendarMonthProps {
  /** Events keyed by ISO date (YYYY-MM-DD). */
  events?: Record<string, CalendarEvent[]>
  className?: string
}

const CAL_STYLE: Record<CalendarId, { label: string; chip: string; dot: string }> = {
  product: { label: 'Product', chip: 'bg-primary/15 text-primary', dot: 'bg-primary' },
  design: { label: 'Design', chip: 'bg-sky-500/15 text-sky-500', dot: 'bg-sky-500' },
  personal: { label: 'Personal', chip: 'bg-emerald-500/15 text-emerald-500', dot: 'bg-emerald-500' },
}

const DEFAULT_EVENTS: Record<string, CalendarEvent[]> = {
  '2026-08-03': [{ label: 'Sprint 42 kickoff', calendar: 'product' }],
  '2026-08-06': [{ label: 'Design crit', calendar: 'design' }],
  '2026-08-13': [{ label: 'v3.1 release', calendar: 'product' }],
  '2026-08-17': [{ label: 'Flight to Lisbon', calendar: 'personal' }],
  '2026-08-20': [
    { label: 'Roadmap review', calendar: 'product' },
    { label: 'Portfolio review', calendar: 'design' },
    { label: 'Dentist, 15:30', calendar: 'personal' },
    { label: '1:1 with Sam', calendar: 'product' },
  ],
  '2026-08-27': [{ label: 'Q3 planning', calendar: 'product' }],
}

const WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
const MONTHS = [
  'January', 'February', 'March', 'April', 'May', 'June',
  'July', 'August', 'September', 'October', 'November', 'December',
]

const TODAY_ISO = '2026-08-13'
/** Monday before Aug 1, 2026 (a Saturday) — the grid's first cell. */
const FIRST_CELL_UTC = Date.UTC(2026, 6, 27)
const MAX_CHIPS = 2

interface DayCell {
  iso: string
  day: number
  monthName: string
  inMonth: boolean
}

function buildWeeks(): DayCell[][] {
  const cells: DayCell[] = Array.from({ length: 42 }, (_, i) => {
    const date = new Date(FIRST_CELL_UTC + i * 86_400_000)
    return {
      iso: date.toISOString().slice(0, 10),
      day: date.getUTCDate(),
      monthName: MONTHS[date.getUTCMonth()],
      inMonth: date.getUTCMonth() === 7,
    }
  })
  return Array.from({ length: 6 }, (_, w) => cells.slice(w * 7, w * 7 + 7))
}

const WEEKS = buildWeeks()

export function CalendarMonth({ events = DEFAULT_EVENTS, className = '' }: CalendarMonthProps) {
  return (
    <section className={`w-full ${className}`}>
      <div className="mb-4 flex flex-wrap items-center gap-3">
        <h2 className="text-lg font-bold tracking-tight">August 2026</h2>

        <ul className="flex items-center gap-3 text-xs text-muted-foreground sm:ms-4">
          {(Object.keys(CAL_STYLE) as CalendarId[]).map((id) => (
            <li key={id} className="flex items-center gap-1.5">
              <span aria-hidden className={`h-2 w-2 rounded-full border border-transparent ${CAL_STYLE[id].dot}`} />
              {CAL_STYLE[id].label}
            </li>
          ))}
        </ul>

        <div className="ms-auto flex items-center gap-1">
          <button
            type="button"
            aria-label="Previous month"
            className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border/60 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
          >
            <ChevronLeft aria-hidden className="h-4 w-4 rtl:rotate-180" />
          </button>
          <button
            type="button"
            aria-label="Next month"
            className="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border/60 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
          >
            <ChevronRight aria-hidden className="h-4 w-4 rtl:rotate-180" />
          </button>
          <button
            type="button"
            className="ms-1 rounded-lg border border-border/60 px-3 py-1.5 text-sm font-medium transition-colors hover:bg-muted"
          >
            Today
          </button>
        </div>
      </div>

      <div
        role="grid"
        aria-label="August 2026"
        className="overflow-hidden rounded-xl border border-border/60"
      >
        <div role="row" className="grid grid-cols-7 gap-px bg-border/60">
          {WEEKDAYS.map((weekday) => (
            <span
              key={weekday}
              role="columnheader"
              className="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground"
            >
              {weekday}
            </span>
          ))}
        </div>

        {WEEKS.map((week) => (
          <div key={week[0].iso} role="row" className="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
            {week.map((cell) => {
              const dayEvents = events[cell.iso] ?? []
              const overflow = dayEvents.length - MAX_CHIPS
              const isToday = cell.iso === TODAY_ISO
              return (
                <div key={cell.iso} role="gridcell" className={cell.inMonth ? 'bg-card' : 'bg-muted/30'}>
                  <button
                    type="button"
                    aria-label={`${cell.day} ${cell.monthName} 2026${
                      dayEvents.length ? `, ${dayEvents.length} event${dayEvents.length > 1 ? 's' : ''}` : ''
                    }`}
                    aria-current={isToday ? 'date' : undefined}
                    className="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50"
                  >
                    <span
                      className={`inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs ${
                        isToday
                          ? 'font-bold ring-2 ring-primary'
                          : cell.inMonth
                            ? 'font-medium'
                            : 'text-muted-foreground/85'
                      }`}
                    >
                      {cell.day}
                    </span>

                    {dayEvents.slice(0, MAX_CHIPS).map((event) => (
                      <span
                        key={event.label}
                        className={`block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium ${CAL_STYLE[event.calendar].chip}`}
                      >
                        {event.label}
                      </span>
                    ))}

                    {overflow > 0 ? (
                      <span className="px-1.5 text-[0.65rem] font-medium text-muted-foreground">
                        +{overflow} more
                      </span>
                    ) : null}
                  </button>
                </div>
              )
            })}
          </div>
        ))}
      </div>
    </section>
  )
}

Before you paste

  • Styling is Tailwind utility classes on semantic tokens (bg-card, text-muted-foreground) — it inherits your theme instead of overriding it.
  • Install: npm i lucide-react
  • Every prop has a default, so it renders standalone before you wire it up.

Where it goes

Drop it at components/calendar-month.tsx and import it where you need the section:

import { CalendarMonth } from '@/components/calendar-month'

Props

Read out of the component’s own type and signature, so this cannot drift from the source below. Every prop has a default — the component renders standalone before you pass it anything.

PropTypeDefault
eventsEvents keyed by ISO date (YYYY-MM-DD).Record<string, CalendarEvent[]>DEFAULT_EVENTS, className = ''
classNamestring—

Not using React?

The same block rendered once to markup, wrapped as a file your framework compiles. Tailwind classes are framework-agnostic, so the design transfers intact — the behaviour does not.

calendar-month.html
<!--
  Month Calendar Grid — markup from the Hoverlab catalog.

  This is the block rendered once to HTML and wrapped as a component
  file. It is not a port of the React source: the Tailwind classes carry
  the design, which is the part that took the work, and they are the same
  in every framework.

  This block has no interactive behaviour, so nothing is missing.
-->
<section class="w-full ">
  <div class="mb-4 flex flex-wrap items-center gap-3">
    <h2 class="text-lg font-bold tracking-tight">August 2026</h2>
    <ul class="flex items-center gap-3 text-xs text-muted-foreground sm:ms-4">
      <li class="flex items-center gap-1.5"><span aria-hidden="true" class="h-2 w-2 rounded-full border border-transparent bg-primary"></span>Product</li>
      <li class="flex items-center gap-1.5"><span aria-hidden="true" class="h-2 w-2 rounded-full border border-transparent bg-sky-500"></span>Design</li>
      <li class="flex items-center gap-1.5"><span aria-hidden="true" class="h-2 w-2 rounded-full border border-transparent bg-emerald-500"></span>Personal</li>
    </ul>
    <div class="ms-auto flex items-center gap-1">
      <button type="button" aria-label="Previous month" class="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border/60 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-left h-4 w-4 rtl:rotate-180" aria-hidden="true">
          <path d="m15 18-6-6 6-6"></path>
        </svg>
      </button>
      <button type="button" aria-label="Next month" class="inline-flex h-8 w-8 items-center justify-center rounded-lg border border-border/60 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chevron-right h-4 w-4 rtl:rotate-180" aria-hidden="true">
          <path d="m9 18 6-6-6-6"></path>
        </svg>
      </button>
      <button type="button" class="ms-1 rounded-lg border border-border/60 px-3 py-1.5 text-sm font-medium transition-colors hover:bg-muted">Today</button>
    </div>
  </div>
  <div role="grid" aria-label="August 2026" class="overflow-hidden rounded-xl border border-border/60">
    <div role="row" class="grid grid-cols-7 gap-px bg-border/60">
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Mon</span>
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Tue</span>
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Wed</span>
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Thu</span>
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Fri</span>
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Sat</span>
      <span role="columnheader" class="min-w-0 truncate bg-muted/60 px-2 py-2 text-center text-xs font-semibold text-muted-foreground">Sun</span>
    </div>
    <div role="row" class="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="27 July 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">27</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="28 July 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">28</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="29 July 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">29</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="30 July 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">30</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="31 July 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">31</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="1 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">1</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="2 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">2</span>
        </button>
      </div>
    </div>
    <div role="row" class="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="3 August 2026, 1 event" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">3</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-primary/15 text-primary">Sprint 42 kickoff</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="4 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">4</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="5 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">5</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="6 August 2026, 1 event" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">6</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-sky-500/15 text-sky-500">Design crit</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="7 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">7</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="8 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">8</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="9 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">9</span>
        </button>
      </div>
    </div>
    <div role="row" class="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="10 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">10</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="11 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">11</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="12 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">12</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="13 August 2026, 1 event" aria-current="date" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-bold ring-2 ring-primary">13</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-primary/15 text-primary">v3.1 release</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="14 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">14</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="15 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">15</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="16 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">16</span>
        </button>
      </div>
    </div>
    <div role="row" class="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="17 August 2026, 1 event" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">17</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-emerald-500/15 text-emerald-500">Flight to Lisbon</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="18 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">18</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="19 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">19</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="20 August 2026, 4 events" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">20</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-primary/15 text-primary">Roadmap review</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-sky-500/15 text-sky-500">Portfolio review</span>
          <span class="px-1.5 text-[0.65rem] font-medium text-muted-foreground">+2 more</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="21 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">21</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="22 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">22</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="23 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">23</span>
        </button>
      </div>
    </div>
    <div role="row" class="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="24 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">24</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="25 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">25</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="26 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">26</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="27 August 2026, 1 event" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">27</span>
          <span class="block truncate rounded px-1.5 py-0.5 text-[0.65rem] font-medium bg-primary/15 text-primary">Q3 planning</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="28 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">28</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="29 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">29</span>
        </button>
      </div>
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="30 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">30</span>
        </button>
      </div>
    </div>
    <div role="row" class="grid grid-cols-7 gap-px border-t border-border/60 bg-border/60">
      <div role="gridcell" class="bg-card">
        <button type="button" aria-label="31 August 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs font-medium">31</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="1 September 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">1</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="2 September 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">2</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="3 September 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">3</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="4 September 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">4</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="5 September 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">5</span>
        </button>
      </div>
      <div role="gridcell" class="bg-muted/30">
        <button type="button" aria-label="6 September 2026" class="flex min-h-[5.25rem] w-full flex-col items-stretch gap-1 p-1.5 text-start transition-colors hover:bg-muted/50">
          <span class="inline-flex h-6 w-6 items-center justify-center self-start rounded-full text-xs text-muted-foreground/85">6</span>
        </button>
      </div>
    </div>
  </div>
</section>
  • This is rendered HTML, not a translation of the React source. The Tailwind classes carry the design and work in any framework.
  • It is one frame: the component in its initial state, with no props applied beyond the defaults.
  • Requires Tailwind, and the design tokens the classes reference (bg-card, text-muted-foreground, and so on). The template ZIPs ship a globals.css that defines them.

What each framework gets across the whole catalog — effects convert properly; this rung is markup.

For AI

The component, its props, the design tokens it expects and the command that installs it — as one prompt. Paste it into Claude, Cursor, v0 or ChatGPT and what they build around it will match the rest of the catalog instead of inventing its own system.

See the prompt

Used in these pages

Want the whole screen instead of this one section? Open a page and copy it entire.

2 more blocks in Scheduling & Calendar

All of them free to read, copy and install — no account, no locked tiles, no watermarked preview. The whole catalog is open, and so are the API and the CLI.

Browse Scheduling & Calendar

Shipping one commercially

Copying the code is free. Putting it in client work or a paid product is what Pro is for — the licence, not the access.

  • A commercial licence for everything in the catalog
  • Unlimited bundle exports, in Vue, Svelte and Tailwind
  • One payment — no subscription, nothing to renew
Pro — $79 once

More Scheduling & Calendar blocks

View category
Open the full page for this block

Meeting Scheduler

Day strip, slot grid and a time zone the visitor can change — because a slot list with no zone on it is how this pattern wastes an hour of everyone involved.

Scheduling & Calendar334 lines1 dep
Open the full page for this block

Conference Agenda Grid

Time down the side, tracks across, breaks spanning the width — the one comparison a month view cannot make. Falls to a linear list on a phone, from the same array.

Scheduling & Calendar397 lines1 dep