Hone logo
Hone
Problems

Build a Reusable React Date Picker Component

This challenge asks you to create a fully functional and accessible date picker component in React using TypeScript. A well-designed date picker is a fundamental UI element for any application that deals with scheduling, booking, or data entry involving dates.

Problem Description

Your task is to build a self-contained, reusable DatePicker React component. This component should allow users to select a date from a calendar interface.

Key Requirements:

  • Calendar Display: The component must render a monthly calendar view.
  • Date Navigation: Users should be able to navigate between months (previous/next month) and years (optional, but highly recommended).
  • Date Selection: Users should be able to click on a specific day to select it.
  • Selected Date Indication: The currently selected date should be visually highlighted.
  • Current Month Indication: The current month and year should be clearly displayed.
  • Props: The component should accept essential props such as an initial selected date, an onChange callback function to notify the parent component when a date is selected, and potentially props for disabling dates or setting a minimum/maximum date range.
  • Accessibility: The component should be keyboard navigable and have appropriate ARIA attributes for screen reader users.
  • Styling: The component should be styled to be presentable, but the primary focus is on functionality. You can use CSS Modules, styled-components, or plain CSS.
  • TypeScript: The entire component and its props must be written in TypeScript for strong typing.

Expected Behavior:

  1. When the DatePicker component mounts, it should display the calendar for the month of the initialSelectedDate (or the current month if initialSelectedDate is not provided).
  2. Users can click on navigation arrows to move to the previous or next month.
  3. Users can click on a day to select it. Upon selection, the onChange prop should be called with the selected date.
  4. The selected date should be visually distinct.
  5. Navigating away from the selected month and then back should still highlight the selected date.

Edge Cases:

  • Handling leap years correctly for February.
  • Ensuring that days from the previous or next month, when displayed in the current month's view, are visually distinct and non-selectable (or handled appropriately based on your design).
  • What happens when no date is initially selected?
  • How to handle date ranges (minimum/maximum dates).

Examples

Example 1: Basic Usage

// Parent Component
import React, { useState } from 'react';
import DatePicker from './DatePicker'; // Assuming DatePicker is in './DatePicker'

function App() {
  const [selectedDate, setSelectedDate] = useState<Date | null>(new Date());

  const handleDateChange = (date: Date | null) => {
    setSelectedDate(date);
  };

  return (
    <div>
      <h1>My App</h1>
      <DatePicker selectedDate={selectedDate} onChange={handleDateChange} />
      {selectedDate && <p>Selected: {selectedDate.toDateString()}</p>}
    </div>
  );
}

export default App;

Output (Conceptual): A DatePicker component will be rendered. If selectedDate is new Date(), the calendar will show the current month, and today's date will be highlighted. Clicking on a different date will update the selectedDate state in the App component, and the paragraph will display the new date.

Example 2: Initial Date and Navigation

// Parent Component
import React, { useState } from 'react';
import DatePicker from './DatePicker';

function App() {
  const [selectedDate, setSelectedDate] = useState<Date | null>(new Date(2023, 9, 15)); // October 15, 2023

  const handleDateChange = (date: Date | null) => {
    setSelectedDate(date);
  };

  return (
    <div>
      <h1>Event Planner</h1>
      <DatePicker selectedDate={selectedDate} onChange={handleDateChange} />
      {selectedDate && <p>Event Date: {selectedDate.toDateString()}</p>}
    </div>
  );
}

export default App;

Output (Conceptual): The DatePicker will initially display the calendar for October 2023, with the 15th highlighted. Users can click the "next" arrow to go to November 2023, and the "previous" arrow to go back to September 2023. Selecting a new date will update the selectedDate state.

Example 3: Disabling Dates (Advanced Feature - Optional for initial implementation)

// Parent Component
import React, { useState } from 'react';
import DatePicker from './DatePicker';

function App() {
  const [selectedDate, setSelectedDate] = useState<Date | null>(null);

  const handleDateChange = (date: Date | null) => {
    setSelectedDate(date);
  };

  // Function to disable weekends
  const isWeekend = (date: Date): boolean => {
    const dayOfWeek = date.getDay();
    return dayOfWeek === 0 || dayOfWeek === 6; // Sunday or Saturday
  };

  return (
    <div>
      <h1>Booking System</h1>
      <DatePicker
        selectedDate={selectedDate}
        onChange={handleDateChange}
        isDateDisabled={isWeekend} // Pass a function to disable dates
      />
      {selectedDate && <p>Booking for: {selectedDate.toDateString()}</p>}
    </div>
  );
}

export default App;

Output (Conceptual): The DatePicker will render. All weekend days (Saturdays and Sundays) will be visually indicated as disabled and will not be clickable for selection.

Constraints

  • React Version: Use React 18 or later.
  • TypeScript Version: Use TypeScript 4.0 or later.
  • Dependencies: You may use standard JavaScript date manipulation libraries (like date-fns or moment.js for easier date calculations, or implement it yourself). Avoid using pre-built calendar/date picker libraries.
  • State Management: Use React's built-in state management (useState, useReducer).
  • Component Structure: The DatePicker component should be a single functional component or a small set of related components that are easily importable.

Notes

  • Consider how you will represent dates internally (e.g., Date objects in JavaScript).
  • Think about how to calculate the first day of the week and the number of days in each month, including leap years.
  • For accessibility, ensure focus management is handled correctly when navigating between months or selecting dates.
  • Consider adding prop types for better developer experience and safety.
  • The onChange callback should receive null if the user deselects a date or if there's no date selected.
  • For the isDateDisabled prop (if implemented), it should accept a Date object and return a boolean: true if the date should be disabled, false otherwise.
Loading editor...
typescript