React Date Picker Component with TypeScript
This challenge asks you to build a reusable date picker component in React using TypeScript. A date picker is a common UI element allowing users to easily select dates from a calendar interface, and this component will provide a clean and functional way to integrate date selection into your React applications. This exercise will test your understanding of React component creation, state management, event handling, and TypeScript typing.
Problem Description
You are tasked with creating a DatePicker component that allows users to select a date. The component should display a calendar and enable users to navigate between months and years. Upon selecting a date, the component should update its internal state to reflect the selected date and optionally provide a callback function to notify the parent component of the selection.
Key Requirements:
- Calendar Display: The component must display a calendar grid showing days of the week (Sunday - Saturday) and dates for the current month.
- Navigation: Provide buttons or controls to navigate to the previous and next month and year.
- Date Selection: Allow users to click on dates within the calendar to select them.
- State Management: Maintain the currently selected date in the component's state.
- Callback Function (Optional): Accept an optional
onDateChangeprop, which is a function that will be called with the selected date whenever the date changes. - Clear Visual Indication: Clearly indicate the currently selected date within the calendar.
- Disable Past Dates: Dates prior to the current date should be disabled and unselectable.
Expected Behavior:
- The component should render a calendar for the current month when initially mounted.
- Clicking on a date should update the component's state with the selected date and, if provided, call the
onDateChangecallback. - Navigation buttons should update the calendar to display the corresponding month and year.
- Disabled dates should not be selectable.
- The component should handle edge cases such as invalid dates gracefully.
Edge Cases to Consider:
- Handling leap years correctly.
- Ensuring the calendar displays the correct day of the week for the first day of the month.
- Handling cases where the
onDateChangecallback is not provided. - Preventing the user from selecting dates in the past.
Examples
Example 1:
Input: Initial month: January 2024, No selected date, onDateChange is a function that logs the selected date.
Output: A calendar displaying January 2024, with no date highlighted. Clicking on January 15th calls onDateChange with '2024-01-15'.
Explanation: The component renders the calendar for January 2024. Selecting a date updates the state and invokes the provided callback.
Example 2:
Input: Initial month: December 2023, Selected date: '2023-12-25', onDateChange is undefined.
Output: A calendar displaying December 2023, with December 25th highlighted. Clicking on December 31st updates the internal state to '2023-12-31' but does not call any callback.
Explanation: The component renders the calendar for December 2023, highlighting the pre-selected date. Selecting a new date updates the internal state.
Example 3: (Edge Case)
Input: Initial month: February 2024, onDateChange is a function.
Output: A calendar displaying February 2024, correctly accounting for the leap year.
Explanation: The component correctly displays the calendar for a leap year month.
Constraints
- The component should be implemented using functional components and React hooks.
- The date format should be 'YYYY-MM-DD'.
- The component should be reasonably performant; avoid unnecessary re-renders.
- The component should be styled using basic CSS (no external styling libraries are required for this challenge).
- The component should be reusable and accept props for customization (e.g., initial date, onDateChange).
Notes
- Consider using the
Dateobject in JavaScript for date manipulation. - Think about how to efficiently calculate the days of the week for each month.
- Focus on creating a clean and well-structured component with clear separation of concerns.
- You can assume the user will only interact with the component through the provided UI elements (clicking dates, navigating months/years). No direct date input is required.
- Error handling is not a primary focus of this challenge, but consider how to handle invalid date selections gracefully.