Gecko UIGecko UI

Calendar

Interactive calendar component for date selection with month/year navigation

Calendar

An interactive calendar component for selecting dates. Features month/year navigation, three view modes (day/month/year), and programmatic control via ref.

Installation

import { Calendar } from '@geckoui/geckoui';

Basic Usage

SMTWTFS
'use client';

import { useState } from 'react';
import { Calendar } from '@geckoui/geckoui';

function Example() {
  const [selectedDate, setSelectedDate] = useState<string | undefined>();

  return (
    <div className="space-y-4">
      <Calendar selectedDate={selectedDate} onSelectDate={setSelectedDate} />
      {selectedDate && <p className="text-sm text-gray-600">Selected: {selectedDate}</p>}
    </div>
  );
}

Props API

Single Mode Props

PropTypeDefaultDescription
mode'single''single'Selection mode for single date
selectedDatestring | null | undefined-Currently selected date in YYYY-MM-DD format
onSelectDate(date: string) => void-Callback when date is selected

Range Mode Props

PropTypeDefaultDescription
mode'range'-Selection mode for date range
selectedRangeDateRange-Selected date range with from and to
onSelectRange(range: DateRange | null) => void-Callback when range is selected
numberOfMonths1 | 22Number of months to display side by side

Common Props

PropTypeDefaultDescription
calendarRefReact.Ref<CalendarRef>-Ref for programmatic control
classNamestring-Additional CSS classes
styleReact.CSSProperties-Inline styles
disableDate(date: string) => boolean-Callback to determine if a date should be disabled
renderDayCell(props: DayCellRenderProps) => ReactNode-Custom renderer for day cells

DateRange Type

interface DateRange {
  from: string | null;  // ISO format: 'YYYY-MM-DD'
  to?: string | null;   // ISO format: 'YYYY-MM-DD'
}

DayCellRenderProps Type

interface DayCellRenderProps {
  day: number;
  month: number;
  year: number;
  date: string;        // 'YYYY-MM-DD' format
  isDisabled: boolean;
  isSelected: boolean;
  isFocusedMonth: boolean; // true if the day is in the current month being viewed
}

Date Format

All dates must be in ISO format: YYYY-MM-DD

// ✅ Correct
selectedDate="2024-12-25"
selectedDate="2024-01-01"

// ❌ Incorrect
selectedDate="12/25/2024"
selectedDate="25-12-2024"

The component validates the date format and logs an error if invalid.

Examples

With Default Date

Pre-select a date when the calendar loads:

SMTWTFS

Selected: 2024-06-15

const [selectedDate, setSelectedDate] = useState<string | undefined>('2024-06-15');

<Calendar selectedDate={selectedDate} onSelectDate={setSelectedDate} />

Use Cases:

  • Highlight today's date
  • Mark important dates (holidays, events)
  • Show reference dates while selecting

Programmatic Control

Navigate to specific months/years using calendarRef:

SMTWTFS
'use client';

import { useState, useRef } from 'react';
import { Calendar, Button } from '@geckoui/geckoui';
import type { CalendarRef } from '@geckoui/geckoui';

function Example() {
  const [selectedDate, setSelectedDate] = useState<string | undefined>();
  const calendarRef = useRef<CalendarRef>(null);

  const jumpToDate = (month: number, year: number) => {
    calendarRef.current?.moveTo(month, year);
  };

  return (
    <div className="space-y-4">
      <div className="flex gap-2">
        <Button size="sm" variant="outlined" onClick={() => jumpToDate(1, 2025)}>
          January 2025
        </Button>
        <Button size="sm" variant="outlined" onClick={() => jumpToDate(7, 2024)}>
          July 2024
        </Button>
        <Button size="sm" variant="outlined" onClick={() => jumpToDate(12, 2023)}>
          December 2023
        </Button>
      </div>
      <Calendar
        selectedDate={selectedDate}
        onSelectDate={setSelectedDate}
        calendarRef={calendarRef}
      />
    </div>
  );
}

CalendarRef API

interface CalendarRef {
  moveTo: (month: number, year: number) => void;
}

Parameters:

  • month: 1-12 (January = 1, December = 12)
  • year: Full year (e.g., 2024, 2025)

Behavior:

  • Switches view to Day mode
  • Displays the specified month/year
  • Does NOT select a date (only navigates)

Range Mode

Use mode="range" to enable date range selection with a dual-month calendar display.

SMTWTFS
SMTWTFS
'use client';

import { useState } from 'react';
import { Calendar } from '@geckoui/geckoui';
import type { DateRange } from '@geckoui/geckoui';

function Example() {
  const [selectedRange, setSelectedRange] = useState<DateRange | undefined>();

  return (
    <Calendar
      mode="range"
      selectedRange={selectedRange}
      onSelectRange={(range) => setSelectedRange(range ?? undefined)}
    />
  );
}

Single Month Display

Use numberOfMonths={1} for a compact single-month range picker:

SMTWTFS
<Calendar
  mode="range"
  selectedRange={selectedRange}
  onSelectRange={(range) => setSelectedRange(range ?? undefined)}
  numberOfMonths={1}
/>

Disable Dates

Use disableDate to prevent selection of specific dates. The callback receives a date string in YYYY-MM-DD format and returns true to disable the date.

SMTWTFS
'use client';

import { useState } from 'react';
import { Calendar } from '@geckoui/geckoui';

function Example() {
  const [selectedDate, setSelectedDate] = useState<string | undefined>();

  const disableDate = (date: string) => {
    const dayOfWeek = new Date(date).getDay();
    return dayOfWeek === 0 || dayOfWeek === 6; // Disable weekends
  };

  return (
    <Calendar
      selectedDate={selectedDate}
      onSelectDate={setSelectedDate}
      disableDate={disableDate}
    />
  );
}

Common Use Cases:

  • Disable weekends
  • Disable past dates
  • Disable holidays or specific dates
  • Disable dates outside a valid range

Custom Day Rendering

Use renderDayCell to customize how each day cell is displayed. This allows adding custom styling, indicators, or content to specific dates.

SMTWTFS
'use client';

import { useState } from 'react';
import { Calendar } from '@geckoui/geckoui';
import type { DayCellRenderProps } from '@geckoui/geckoui';

function Example() {
  const [selectedDate, setSelectedDate] = useState<string | undefined>();

  const hasEvent = (date: string) => {
    const today = new Date();
    return today.getDate() === new Date(date).getDate();
  };

  return (
    <div className="space-y-4">
      <Calendar
        selectedDate={selectedDate}
        onSelectDate={setSelectedDate}
        renderDayCell={({ day, date }) => (
          <>
            <span>{day}</span>
            {hasEvent(date) && (
              <span className="absolute top-1 right-1 w-1.5 h-1.5 bg-red-500 rounded-full" />
            )}
          </>
        )}
      />
      {selectedDate && <p className="text-sm text-gray-600">Selected: {selectedDate}</p>}
    </div>
  );
}

Common Use Cases:

  • Add event indicators or dots
  • Show custom styling for holidays
  • Display additional information on hover
  • Highlight specific date ranges

Styling

The component uses BEM-style class names:

Main Container:

  • GeckoUICalendar - Main container
  • GeckoUICalendar--calendars-2 - Dual calendar mode modifier
  • GeckoUICalendar__dual - Dual calendar wrapper
  • GeckoUICalendar__dual--first / GeckoUICalendar__dual--second - First/second calendar

Header:

  • GeckoUICalendar__header - Header container
  • GeckoUICalendar__header__title - Month/year title
  • GeckoUICalendar__header__title--clickable - Clickable title state
  • GeckoUICalendar__header__arrow-button - Navigation arrow buttons
  • GeckoUICalendar__header__arrow-left-icon / GeckoUICalendar__header__arrow-right-icon - Arrow icons

Year Picker:

  • GeckoUICalendar__year-picker - Year picker grid
  • GeckoUICalendar__year-picker__button - Year button
  • GeckoUICalendar__year-picker__button--selected - Selected year
  • GeckoUICalendar__year-picker__button--prev-next - Previous/next year buttons

Month Picker:

  • GeckoUICalendar__month-picker - Month picker grid
  • GeckoUICalendar__month-picker__button - Month button
  • GeckoUICalendar__month-picker__button--selected - Selected month

Day Picker:

  • GeckoUICalendar__day-picker-weekdays - Weekday header row
  • GeckoUICalendar__day-picker - Day picker grid
  • GeckoUICalendar__day-picker__button - Day button
  • GeckoUICalendar__day-picker__button--today - Today's date
  • GeckoUICalendar__day-picker__button--selected - Selected date
  • GeckoUICalendar__day-picker__button--disabled - Disabled date
  • GeckoUICalendar__day-picker__button--active-month-false - Dates outside current month
  • GeckoUICalendar__day-picker__button--in-range - Date within selected range
  • GeckoUICalendar__day-picker__button--range-start - Range start date
  • GeckoUICalendar__day-picker__button--range-end - Range end date
  • GeckoUICalendar__day-picker__button--hover-preview - Hover preview for range selection
  • GeckoUICalendar__day-picker__button--hover-preview-start / GeckoUICalendar__day-picker__button--hover-preview-end - Hover preview boundaries

Accessibility

  • Semantic HTML with proper table structure for day grid
  • Keyboard navigation with arrow keys
  • Tab to focus navigation buttons
  • Enter/Space to select dates
  • Screen reader announcements for date selection
  • ARIA labels for navigation controls

Best Practices

  1. Always use ISO format: Use YYYY-MM-DD for all date values
  2. Validate dates: Check date ranges and constraints in onSelectDate
  3. Clear selection: Provide a way to clear the selected date
  4. Form integration: Disable submit until date is selected
  5. Error handling: Show validation errors near the calendar
  6. Responsive design: Calendar adapts to container width