Skip to main content

Custom Components

Use the components prop when styling hooks are not enough and you need to replace internal parts with your own React components.

Component structure

<CalendarContainer>
<MonthContainer>
<MonthArrowBack />
<MonthContent />
<MonthArrowNext />
</MonthContainer>

<WeekContainer>
<WeekContent />
</WeekContainer>

<DaysContainer>
<DayContainer>
<DayContent />
<DayToday />
<DaySelection />
<DayReservation />
</DayContainer>
</DaysContainer>
</CalendarContainer>

Custom component overrides

Swap only the internal pieces you need while keeping the booking logic and state model intact.

Live example
Loading interactive preview...
import {
Calendar,
DaySelectionProps,
MonthContentProps,
} from "@demark-pro/react-booking-calendar";

const MonthContent = ({
month,
year,
options,
innerProps,
getClassNames,
}: MonthContentProps) => {
const { className = "", ...restInnerProps } = innerProps ?? {};

return (
<div
className={getClassNames("MonthContent", className)}
{...restInnerProps}
>
{new Date(year, month).toLocaleDateString(options?.locale, {
month: "short",
calendar: "gregory",
})}
<strong>
{new Intl.NumberFormat(options?.locale, {
useGrouping: false,
}).format(year)}
</strong>
</div>
);
};

const DaySelection = ({
state,
innerProps,
getClassNames,
}: DaySelectionProps) => {
const { className = "", ...restInnerProps } = innerProps ?? {};

if (!state.isSelected && !state.isSelectedStart && !state.isSelectedEnd) {
return null;
}

return (
<div
className={getClassNames("DaySelection", className)}
{...restInnerProps}
>
{state.isSelectedStart ? "Start" : state.isSelectedEnd ? "End" : "Stay"}
</div>
);
};

<Calendar
range
selected={selected}
reserved={reserved}
onChange={setSelected}
components={{
MonthContent,
DaySelection,
}}
/>;

Event markers under dates

This pattern works well for booking dashboards, events calendars, and internal ops views where each day needs extra status markers below the date label.

Events calendar with markers

A custom `DayContent` override can keep the default selection behavior and still render event dots under each date.

Live example
Loading interactive preview...
import { useState } from "react";
import { Calendar } from "@demark-pro/react-booking-calendar";

const events = [
{ date: new Date(2030, 4, 12), color: "#0d8b84" },
{ date: new Date(2030, 4, 12), color: "#f6b048" },
{ date: new Date(2030, 4, 14), color: "#f36c3d" },
];

const dayKey = (date) =>
String(date.getFullYear()) +
"-" +
String(date.getMonth()) +
"-" +
String(date.getDate());

const markersByDay = events.reduce((acc, item) => {
const key = dayKey(item.date);

if (!acc[key]) acc[key] = [];
acc[key].push(item);

return acc;
}, {});

const DayContent = ({
children,
date,
state,
innerProps,
getClassNames,
}) => {
const { className = "", ...restInnerProps } = innerProps ?? {};
const markers = markersByDay[dayKey(date)] ?? [];

return (
<div className={getClassNames("DayContent", className)} {...restInnerProps}>
<span>{children}</span>
{state.isSameMonth && markers.length > 0 ? (
<span>
{markers.slice(0, 3).map((marker, index) => (
<span
key={index}
style={{ backgroundColor: marker.color }}
/>
))}
</span>
) : null}
</div>
);
};

<Calendar
selected={selected}
onChange={setSelected}
components={{ DayContent }}
/>;

Important rule

Define replacement components outside the render path. Recreating them inline on every render can cause remounts and state loss.

If your override formats built-in calendar dates, keep the output on the Gregorian calendar so it stays aligned with the rendered grid.

Using innerProps

Every replacement component receives the functional props it needs through innerProps. Spread them unless you intentionally want to replace behavior:

const DaySelection = ({ innerProps, getClassNames, state }) => {
const { className = "", ...restInnerProps } = innerProps ?? {};

if (!state.isSelected && !state.isSelectedStart && !state.isSelectedEnd) {
return null;
}

return (
<div
className={getClassNames("DaySelection", className)}
{...restInnerProps}
/>
);
};

Exported prop types

The package exports prop types for the replaceable parts, including:

  • CalendarContainerProps
  • MonthContentProps
  • WeekContentProps
  • DayContentProps
  • DaySelectionProps
  • DayReservationProps
  • DayTodayProps

That makes it easier to write strongly typed overrides in TypeScript apps.