Calendar
freeCalendar keeps date choices visible for scheduling, booking, and filter workflows.
dayjs
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
const dateFormatter = new Intl.DateTimeFormat('en', {
dateStyle: 'medium',
});
export default function UsageDemo() {
const [selectedDate, setSelectedDate] = useState<Date | null>(
new Date(2026, 6, 15),
);
return (
<div className="flex w-full max-w-xs flex-col gap-4">
<Calendar
value={selectedDate}
defaultMonth={new Date(2026, 6, 1)}
onChange={(nextDate) => setSelectedDate(nextDate)}
/>
</div>
);
}Installation
Add this component with the NateUI CLI.
npx nateui@latest add CalendarExamples
Basic
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
export default function BasicDemo() {
return (
<Calendar />
);
}Range
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
export default function RangeDemo() {
const [range, setRange] = useState<[Date | null, Date | null]>([
new Date(2026, 6, 8),
new Date(2026, 6, 14),
]);
return (
<Calendar.Range
value={range}
defaultMonth={new Date(2026, 6, 1)}
onChange={(nextRange) => setRange(nextRange)}
/>
);
}Multiple Selection
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
export default function MultipleSelectionDemo() {
const [selectedDates, setSelectedDates] = useState<Date[]>([
new Date(2026, 6, 8),
new Date(2026, 6, 15),
new Date(2026, 6, 22),
]);
return (
<Calendar
multipleSelection
value={selectedDates}
defaultMonth={new Date(2026, 6, 1)}
onChange={(nextDates) => setSelectedDates(nextDates)}
/>
);
}Multiple Views
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
export default function MultipleViewsDemo() {
const [range, setRange] = useState<[Date | null, Date | null]>([
new Date(2026, 6, 10),
new Date(2026, 7, 4),
]);
return (
<div className="w-full max-w-126 flex justify-center">
<Calendar.Range
dateViewCount={2}
value={range}
defaultMonth={new Date(2026, 6, 1)}
onChange={(nextRange) => setRange(nextRange)}
/>
</div>
);
}Disabled Dates
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
const isWeekend = (date: Date) => date.getDay() === 0 || date.getDay() === 6;
export default function DisabledDatesDemo() {
return (
<Calendar
minDate={new Date(2026, 6, 6)}
maxDate={new Date(2026, 6, 24)}
disableDate={isWeekend}
/>
);
}Custom Render
Preview
Dark
| Mo | Tu | We | Th | Fr | Sa | Su |
|---|---|---|---|---|---|---|
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
import Badge from '@/components/ui/Badge';
export default function CustomRenderDemo() {
const [value, setValue] = useState<Date | null>(null);
return (
<div className="mx-auto max-w-[252px] md:w-[252px]">
<Calendar
value={value}
dayClassName={(date, { selected }) => {
if (date.getDate() === 12 && !selected) {
return 'text-red-600';
}
if (selected) {
return 'text-white';
}
return 'text-gray-700 dark:text-gray-200';
}}
dayStyle={(date, { selected, outOfMonth }) => {
if (date.getDate() === 18 && !selected) {
return { color: '#15c39a' };
}
if (outOfMonth) {
return {
opacity: 0,
pointerEvents: 'none',
cursor: 'default',
};
}
return {};
}}
renderDay={(date) => {
const day = date.getDate();
if (day !== 12) {
return <span>{day}</span>;
}
return (
<span className="relative flex justify-center items-center w-full h-full">
{day}
<Badge
className="absolute bottom-1"
innerClass="h-1 w-1"
/>
</span>
);
}}
onChange={setValue}
/>
</div>
);
}Mini
Preview
Dark
July 2026
Mon
Tue
Wed
Thu
Fri
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';
export default function MiniDemo() {
const [selectedDate, setSelectedDate] = useState(new Date(2026, 6, 15));
return (
<div className="w-full max-w-80">
<Calendar.Mini
value={selectedDate}
onChange={(nextDate) => setSelectedDate(nextDate)}
/>
</div>
);
}API
Calendar exposes the main Calendar date grid plus Calendar.Range and Calendar.Mini.
Shared Calendar Props
These props are available on Calendar and Calendar.Range unless noted by the component-specific tables below.
| Prop | Description | Type | Default |
|---|---|---|---|
className | Class names applied to the calendar root. | string | - |
dateViewCount | Number of month views rendered side by side. | number | 1 |
dayClassName | Function that returns class names for each day cell. | CalendarDayClassName | - |
dayStyle | Function that returns inline styles for each day cell. | CalendarDayStyle | - |
defaultMonth | Initial month shown when month is uncontrolled. | Date | new Date() |
defaultView | Initial picker level. | CalendarView | 'date' |
disableDate | Disable individual dates. | CalendarDisableDate | - |
disableOutOfMonth | Disable dates outside the visible month. | boolean | false |
enableHeaderLabel | Allow the month and year labels to switch picker level. | boolean | true |
firstDayOfWeek | First weekday shown in the calendar grid. | FirstDayOfWeek | 'monday' |
focusable | Allow day buttons to participate in keyboard focus. | boolean | true |
fullWidth | Let day cells stretch to the full available table width. | boolean | false |
hideOutOfMonthDates | Hide dates outside the active month instead of muting them. | boolean | false |
hideWeekdays | Hide the weekday header row. | boolean | false |
isDateFirstInRange | Mark custom first-in-range dates. | CalendarDatePredicate | - |
isDateInRange | Mark custom in-range dates. | CalendarDatePredicate | - |
isDateLastInRange | Mark custom last-in-range dates. | CalendarDatePredicate | - |
labelFormat | Month and year format used by the date-view header. | CalendarLabelFormat | { month: 'MMM', year: 'YYYY' } |
locale | Locale passed to date labels. Falls back to ConfigProvider locale. | string | - |
lockView | Keep the current view level after selecting a month or year. | boolean | false |
maxDate | Latest selectable date. | Date | - |
minDate | Earliest selectable date. | Date | - |
month | Controlled visible month. | Date | - |
monthLabelFormat | Month label format used by the month picker. | string | 'MMM' |
onDayMouseEnter | Called when the pointer enters a day cell. | CalendarDayMouseEnterHandler | - |
onMonthChange | Called when the visible month changes. | CalendarMonthChangeHandler | - |
paginateBy | Number of months to move when navigating. | number | dateViewCount |
preventFocus | Prevent mouse down from moving focus into calendar controls. | boolean | false |
range | Highlighted range shown in the date table. Calendar.Range manages this from value. | CalendarRangeHighlight | - |
renderDay | Custom renderer for the content inside each day button. | CalendarRenderDay | - |
weekdayLabelFormat | Weekday label format. | string | 'dd' |
weekendDays | Weekday indexes treated as weekends. | CalendarWeekendDays | [0, 6] |
yearLabelFormat | Year label format used by month/year views. | string | 'YYYY' |
ref | Ref forwarded to the root div. | Ref<HTMLDivElement> | - |
...nativeDivProps | Native props for the root div, excluding onChange and value. | NativeCalendarDivProps | - |
Calendar
| Prop | Description | Type | Default |
|---|---|---|---|
multipleSelection | Toggle between single-date and multi-date selection. | MultipleSelection | false |
value | Controlled selected date or selected date list. | CalendarValue<MultipleSelection> | - |
onChange | Called with the selected date or selected date list. | CalendarChangeHandler<MultipleSelection> | - |
Calendar.Range
| Prop | Description | Type | Default |
|---|---|---|---|
value | Controlled start and end dates for the selected range. | RangeCalendarValue | Required |
onChange | Called when the user changes the start or end of the range. | RangeCalendarChangeHandler | Required |
singleDate | Allow selecting the same date as both the start and end. | boolean | false |
Calendar.Mini
| Prop | Description | Type | Default |
|---|---|---|---|
className | Class names applied to the mini calendar root. | string | - |
value | Controlled selected date. | Date | - |
defaultValue | Initial selected date when uncontrolled. | Date | new Date() |
onChange | Called when the selected mini-calendar date changes. | MiniCalendarChangeHandler | - |
visibleCount | Number of dates shown in the strip. | number | 5 |
locale | Locale passed to mini-calendar labels. Falls back to ConfigProvider locale. | string | - |
weekdayFormat | Weekday label format for the date strip. | string | 'ddd' |
monthFormat | Header month label format. | string | 'MMMM YYYY' |
showHeader | Show the month header and month navigation buttons. | boolean | true |
showStripNavigation | Show previous/next day buttons around the strip. | boolean | true |
ref | Ref forwarded to the root div. | Ref<HTMLDivElement> | - |
...nativeDivProps | Native props for the root div, excluding onChange, value, and defaultValue. | NativeMiniCalendarDivProps | - |
Types
type CalendarView = 'date' | 'month' | 'year';
type FirstDayOfWeek = 'sunday' | 'monday';
type CalendarLabelFormat = { month: string; year: string };
type CalendarWeekendDays = [number, number];
type CalendarDayProps = {
disabled: boolean;
weekend: boolean;
selectedInRange: boolean;
selected: boolean;
inRange: boolean;
firstInRange: boolean;
lastInRange: boolean;
outOfMonth: boolean;
};
type CalendarDayClassName = (
date: Date,
modifiers: CalendarDayProps,
) => string;
type CalendarDayStyle = (
date: Date,
modifiers: CalendarDayProps,
) => CSSProperties;
type CalendarDisableDate = (date: Date) => boolean;
type CalendarDatePredicate =
| (() => boolean)
| ((date: Date, modifiers: CalendarDayProps) => boolean);
type CalendarDayMouseEnterHandler = (
date: Date,
event: MouseEvent<HTMLButtonElement>,
) => void;
type CalendarMonthChangeHandler = (month: Date) => void;
type CalendarRenderDay = (date: Date) => ReactNode;
type CalendarRangeHighlight = [Date, Date];
type CalendarValue<MultipleSelection extends boolean = false> =
MultipleSelection extends true ? Date[] : Date | null;
type CalendarChangeHandler<MultipleSelection extends boolean = false> = (
value: CalendarValue<MultipleSelection>,
) => void;
type RangeCalendarValue = [Date | null, Date | null];
type RangeCalendarChangeHandler = (value: RangeCalendarValue) => void;
type MiniCalendarChangeHandler = (date: Date) => void;
type NativeCalendarDivProps = Omit<ComponentProps<'div'>, 'onChange' | 'value'>;
type NativeMiniCalendarDivProps = Omit<
ComponentProps<'div'>,
'onChange' | 'value' | 'defaultValue'
>;