Calendar

free

Calendar keeps date choices visible for scheduling, booking, and filter workflows.

dayjs
Preview
Dark
MoTuWeThFrSaSu
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 Calendar

Examples

Basic

Preview
Dark
MoTuWeThFrSaSu
import { useState } from 'react';
import Calendar from '@/components/ui/Calendar';

export default function BasicDemo() {

  return (
    <Calendar />
  );
}

Range

Preview
Dark
MoTuWeThFrSaSu
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
MoTuWeThFrSaSu
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
MoTuWeThFrSaSu
MoTuWeThFrSaSu
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
MoTuWeThFrSaSu
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
MoTuWeThFrSaSu
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.

PropDescriptionTypeDefault
classNameClass names applied to the calendar root.string-
dateViewCountNumber of month views rendered side by side.number1
dayClassNameFunction that returns class names for each day cell.CalendarDayClassName-
dayStyleFunction that returns inline styles for each day cell.CalendarDayStyle-
defaultMonthInitial month shown when month is uncontrolled.Datenew Date()
defaultViewInitial picker level.CalendarView'date'
disableDateDisable individual dates.CalendarDisableDate-
disableOutOfMonthDisable dates outside the visible month.booleanfalse
enableHeaderLabelAllow the month and year labels to switch picker level.booleantrue
firstDayOfWeekFirst weekday shown in the calendar grid.FirstDayOfWeek'monday'
focusableAllow day buttons to participate in keyboard focus.booleantrue
fullWidthLet day cells stretch to the full available table width.booleanfalse
hideOutOfMonthDatesHide dates outside the active month instead of muting them.booleanfalse
hideWeekdaysHide the weekday header row.booleanfalse
isDateFirstInRangeMark custom first-in-range dates.CalendarDatePredicate-
isDateInRangeMark custom in-range dates.CalendarDatePredicate-
isDateLastInRangeMark custom last-in-range dates.CalendarDatePredicate-
labelFormatMonth and year format used by the date-view header.CalendarLabelFormat{ month: 'MMM', year: 'YYYY' }
localeLocale passed to date labels. Falls back to ConfigProvider locale.string-
lockViewKeep the current view level after selecting a month or year.booleanfalse
maxDateLatest selectable date.Date-
minDateEarliest selectable date.Date-
monthControlled visible month.Date-
monthLabelFormatMonth label format used by the month picker.string'MMM'
onDayMouseEnterCalled when the pointer enters a day cell.CalendarDayMouseEnterHandler-
onMonthChangeCalled when the visible month changes.CalendarMonthChangeHandler-
paginateByNumber of months to move when navigating.numberdateViewCount
preventFocusPrevent mouse down from moving focus into calendar controls.booleanfalse
rangeHighlighted range shown in the date table. Calendar.Range manages this from value.CalendarRangeHighlight-
renderDayCustom renderer for the content inside each day button.CalendarRenderDay-
weekdayLabelFormatWeekday label format.string'dd'
weekendDaysWeekday indexes treated as weekends.CalendarWeekendDays[0, 6]
yearLabelFormatYear label format used by month/year views.string'YYYY'
refRef forwarded to the root div.Ref<HTMLDivElement>-
...nativeDivPropsNative props for the root div, excluding onChange and value.NativeCalendarDivProps-

Calendar

PropDescriptionTypeDefault
multipleSelectionToggle between single-date and multi-date selection.MultipleSelectionfalse
valueControlled selected date or selected date list.CalendarValue<MultipleSelection>-
onChangeCalled with the selected date or selected date list.CalendarChangeHandler<MultipleSelection>-

Calendar.Range

PropDescriptionTypeDefault
valueControlled start and end dates for the selected range.RangeCalendarValueRequired
onChangeCalled when the user changes the start or end of the range.RangeCalendarChangeHandlerRequired
singleDateAllow selecting the same date as both the start and end.booleanfalse

Calendar.Mini

PropDescriptionTypeDefault
classNameClass names applied to the mini calendar root.string-
valueControlled selected date.Date-
defaultValueInitial selected date when uncontrolled.Datenew Date()
onChangeCalled when the selected mini-calendar date changes.MiniCalendarChangeHandler-
visibleCountNumber of dates shown in the strip.number5
localeLocale passed to mini-calendar labels. Falls back to ConfigProvider locale.string-
weekdayFormatWeekday label format for the date strip.string'ddd'
monthFormatHeader month label format.string'MMMM YYYY'
showHeaderShow the month header and month navigation buttons.booleantrue
showStripNavigationShow previous/next day buttons around the strip.booleantrue
refRef forwarded to the root div.Ref<HTMLDivElement>-
...nativeDivPropsNative 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'
>;