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.