psudo
psudo

Reputation: 1578

Show react calendar on click

I'm using react-calendar package on my react app. Placing <Calendar/> on the file gives the open calendar on the frontend.

But I want to display the calendar if the user clicks the input field:

      <div className="form-group">
        <label>Start Date</label>
        <input type="text"/>
        <Calendar style={{display: "none"}} />
      </div>

I tried through inline style to hide the calendar component and change on click. But the calendar doesn't hide with inline css also.

Gone through documentation also but didn't find any help.

Upvotes: 0

Views: 6420

Answers (2)

SDW
SDW

Reputation: 1910

To achieve this functionality, integrate the react-calendar library beneath the input field. Position the calendar using CSS with position: absolute. Utilize an event listener on the document to detect clicks outside the component, toggling the calendar's visibility accordingly.

First create child component: CalendarInput. Here's a simplified example:

import React, {useState, useRef, useEffect} from "react";
import Calendar from "react-calendar";
import moment from "moment";

const CalendarInput = ({date, setDate}: {
    date: Date;
    setDate: (value: any, event: React.MouseEvent<HTMLButtonElement>) => void;
}) => {
    const [focused, setFocused] = useState(false);
    const calendarRef = useRef<HTMLDivElement>(null);

    useEffect(() => {
        const handleDocumentMousedown = (event: MouseEvent) => {
            if (
                calendarRef.current &&
                !calendarRef.current.contains(event.target as Node)
            ) {
                setFocused(false);
            }
        };

        document.addEventListener("mousedown", handleDocumentMousedown);

        return () => {
            document.removeEventListener("mousedown", handleDocumentMousedown);
        };
    }, []);

    const handleChange = (value: any, event: any) => {
        setDate(value, event);
        setFocused(false);
    };

    const handleInputClick = (event: React.MouseEvent<HTMLInputElement>) => {
        event.stopPropagation();
        setFocused(true);
    };

    return (
        <div className="w-full" ref={calendarRef}>
            <input
                className="input-default"
                value={moment(date).format("DD-MM-YYYY").toString()}
                onClick={handleInputClick}
            />
            {focused && (
                <div className="calendar-container">
                    <Calendar
                        className="absolute"
                        value={date}
                        onChange={handleChange}
                    />
                </div>
            )}
        </div>
    );
};

export default CalendarInput;

Then in your parent component add :

const [date, setDate] = useState(new Date());
<CalendarInput date={date} setDate={setDate} />

Upvotes: 0

Qausim
Qausim

Reputation: 129

It will be best you create a wrapper component around your calendar and input. This way it manages its own showCalendar state and can be reused elsewhere.

import React, { useState } from "react";
import Calendar from "react-calendar";

const ReactCalendarDemo = ({ date, setDate }) => {
  const [showCalendar, setShowCalendar] = useState(false);
  const handleChange = value => {
    setDate(value);
    setShowCalendar(false);
  };

  return (
    <div>
      <input
        value={date.toLocaleDateString()}
        onFocus={() => setShowCalendar(true)}
      />
      <Calendar
        className={showCalendar ? "" : "hide"}
        value={date}
        onChange={handleChange}
      />
    </div>
  );
};

export default ReactCalendarDemo;

You pass in your current date value and its setter as props.

Then you can toggle display in your CSS style using the hide class

.react-calendar.hide {
  display: none;
}

Upvotes: 4

Related Questions