Lesson 3: Building a Grid
Using buildCalendarMonth to generate and render a calendar month grid.
Lesson 3 of 8: use buildCalendarMonth to generate a month grid and render it as a table.
The grid builder
buildCalendarMonth is a pure function. Pass an adapter, a date, and optional config; get back a Grid.ICalendarMonth with weeks and day cells.
import { NativeAdapter, buildCalendarMonth } from '@gentleduck/calendar'
const adapter = new NativeAdapter()
const march2026 = new Date(2026, 2, 1)
const month = buildCalendarMonth(adapter, march2026, {
showOutsideDays: true,
fixedWeeks: false,
})
// month.weeks is an array of Grid.ICalendarWeek objects
// Each week has 7 Grid.ICalendarDay objectsimport { NativeAdapter, buildCalendarMonth } from '@gentleduck/calendar'
const adapter = new NativeAdapter()
const march2026 = new Date(2026, 2, 1)
const month = buildCalendarMonth(adapter, march2026, {
showOutsideDays: true,
fixedWeeks: false,
})
// month.weeks is an array of Grid.ICalendarWeek objects
// Each week has 7 Grid.ICalendarDay objectsWhat you get back
// Grid.ICalendarMonth<Date>
{
month: Date, // First day of the month
weeks: [
{
weekNumber: 9, // ISO week number
days: [
{
date: Date, // The date
isToday: false, // Is this today?
isOutside: true, // From adjacent month?
isHidden: false, // Hidden when showOutsideDays is false?
isWeekend: true, // Saturday or Sunday?
isSelected: false, // Set by applySelection()
isDisabled: false, // Set by applySelection()
isRangeStart: false, // Set by applySelection()
isRangeEnd: false, // Set by applySelection()
isRangeMiddle: false, // Set by applySelection()
},
// ... 6 more days
]
},
// ... more weeks
]
}// Grid.ICalendarMonth<Date>
{
month: Date, // First day of the month
weeks: [
{
weekNumber: 9, // ISO week number
days: [
{
date: Date, // The date
isToday: false, // Is this today?
isOutside: true, // From adjacent month?
isHidden: false, // Hidden when showOutsideDays is false?
isWeekend: true, // Saturday or Sunday?
isSelected: false, // Set by applySelection()
isDisabled: false, // Set by applySelection()
isRangeStart: false, // Set by applySelection()
isRangeEnd: false, // Set by applySelection()
isRangeMiddle: false, // Set by applySelection()
},
// ... 6 more days
]
},
// ... more weeks
]
}Rendering the grid
A minimal React component that renders the grid:
import { NativeAdapter, buildCalendarMonth } from '@gentleduck/calendar'
const adapter = new NativeAdapter()
function StaticCalendar({ date }: { date: Date }) {
const month = buildCalendarMonth(adapter, date, {
showOutsideDays: true,
})
return (
<table>
<thead>
<tr>
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(d => (
<th key={d}>{d}</th>
))}
</tr>
</thead>
<tbody>
{month.weeks.map((week, i) => (
<tr key={i}>
{week.days.map(day => (
<td
key={day.date.getTime()}
style={{
opacity: day.isOutside ? 0.4 : 1,
fontWeight: day.isToday ? 'bold' : 'normal',
}}>
{day.date.getDate()}
</td>
))}
</tr>
))}
</tbody>
</table>
)
}import { NativeAdapter, buildCalendarMonth } from '@gentleduck/calendar'
const adapter = new NativeAdapter()
function StaticCalendar({ date }: { date: Date }) {
const month = buildCalendarMonth(adapter, date, {
showOutsideDays: true,
})
return (
<table>
<thead>
<tr>
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(d => (
<th key={d}>{d}</th>
))}
</tr>
</thead>
<tbody>
{month.weeks.map((week, i) => (
<tr key={i}>
{week.days.map(day => (
<td
key={day.date.getTime()}
style={{
opacity: day.isOutside ? 0.4 : 1,
fontWeight: day.isToday ? 'bold' : 'normal',
}}>
{day.date.getDate()}
</td>
))}
</tr>
))}
</tbody>
</table>
)
}Multi-month grids
buildMultiMonth generates several consecutive months:
import { buildMultiMonth } from '@gentleduck/calendar'
const months = buildMultiMonth(adapter, new Date(), 3, {
showOutsideDays: true,
})
// months[0] - current month
// months[1] - next month
// months[2] - month after nextimport { buildMultiMonth } from '@gentleduck/calendar'
const months = buildMultiMonth(adapter, new Date(), 3, {
showOutsideDays: true,
})
// months[0] - current month
// months[1] - next month
// months[2] - month after nextGrid config options
| Option | Type | Default | Description |
|---|---|---|---|
showOutsideDays | boolean | true | When false, outside days are hidden and disabled |
fixedWeeks | boolean | false | Always produces 6 weeks |
locale | CalendarLocaleConfig | {} | Locale settings (see below) |
locale.weekStartDay sets the first day of the week (0 = Sunday, 1 = Monday). Pass it inside locale:
buildCalendarMonth(adapter, date, {
locale: { weekStartDay: 1 }, // Monday
})buildCalendarMonth(adapter, date, {
locale: { weekStartDay: 1 }, // Monday
})buildCalendarMonth is pure — no state. The next lesson uses useCalendar to add interactivity.