Hacker0x01 / react-datepicker

A simple and reusable datepicker component for React
https://reactdatepicker.com/
MIT License
7.96k stars 2.23k forks source link

customInput typing doesn't work properly #3762

Open Konstiman opened 1 year ago

Konstiman commented 1 year ago

Describe the bug

When I pass a custom input component into the customInput parameter, typing the date using the keyboard becomes buggy - for example it's not possible to rewrite or delete the date.

To Reproduce

I created the following CodeSandbox containing the minimal version of the problem:

https://codesandbox.io/s/react-datepicker-issue-wyunxm?file=/src/index.tsx

The green datepicker uses a native input - I'm passing the <input /> tag into the customInput.

The red datepicker uses a custom component - I'm passing the <CustomInput /> into the customInput.

function App() {
  const [startDate1, setDate1] = React.useState(new Date());
  const [startDate2, setDate2] = React.useState(new Date());

  const CustomInput = React.forwardRef((props: any, ref) => (
    <input {...props} ref={ref} type="text" className="dp-red" />
  ));

  return (
    <div className="App">
      <h1>Simple datepicker</h1>
      <div className="dp-container">
        <DatePicker
          selected={startDate1}
          onChange={setDate1}
          customInput={<input type="text" className="dp-green" />}
        />
      </div>
      <div className="dp-container">
        <DatePicker
          selected={startDate2}
          onChange={setDate2}
          customInput={<CustomInput />}
        />
      </div>
    </div>
  );
}

Expected behavior

The green datepicker behaves correctly when changing the value using the keyboard - it's possible to use backspace and type freely.

The red datepicker should have the same behavior, but it doesn't.

Desktop:

Additional context

Maybe I'm using the forwardRef incorrectly? I don't know, but I also tried passing the ref using the customInputRef parameter and it didn't work either.

Am I doing anything wrong or is this a bug?

jiscsander commented 1 year ago

I've come across the same issue. It seems like every change of input that can be converted to a date triggers the same action as onBlur usually seems to - i.e. if you enter "1" into the custom input box it will automatically convert that to 01/currentMonth/currentYear and same for other numbers.

marten-cz commented 1 year ago

There is this reported issue https://github.com/Hacker0x01/react-datepicker/issues/2051 , but it didn't worked for me.

henkkasoft commented 1 year ago

I am using React-Bootstrap and had this problem when DatePicker was used inside Modal or Accordion/Table components. I was able to fix it using this https://github.com/Hacker0x01/react-datepicker/issues/2051#issuecomment-832719303

With typescript I had a problem with useRef type but was able to solve it with a bit ugly solution.

const CustomInput = forwardRef((props: FormControlProps, ref: React.Ref<HTMLDivElement>) => {
  return (
    <InputGroup className={classes.CustomInput} ref={ref}>
      <Form.Control {...props} />
      <IoCalendarNumberOutline className={classes.CalendarIcon} />
    </InputGroup>
  );
});

function MyDatePicker({ value, onDateChange }: MyDatePickerProps) {
  const refCustomInput = useRef() as React.MutableRefObject<HTMLDivElement>;
  return (
    <DatePicker
      selected={value}
      onChange={onDateChange}
      customInput={<CustomInput ref={refCustomInput} />}
    />
  );
}

By the way pressing the calendar icon IoCalendarNumberOutline is not activating the DatePicker yet in my solution. If someone can tip me how to solve this it would be great.

djwashburn commented 6 months ago

I also had this problem and solved it using mjviljan's comment on 2051 here, and like @henkkasoft above I ran into an issue with the useRef type. I found a cleaner solution than the above for that problem here:

const refCustomInput = useRef<HTMLInputElement>(null);

Basically, you just have to parameterize useRef with the type of the element, and initialize the ref with null.

Hopefully this helps someone. I think the example for Custom Input should be changed accordingly, to prevent people from running into this issue in the future.

aaronamm commented 5 months ago

@djwashburn thank you so much for sharing, I agree with you that the example of a custom input should change to input type.

hebontes commented 1 month ago

Guys update the docs so that customInput example contains <input /> and not <button></button> element! please!

hebontes commented 1 month ago

✅ I solved the issue after incorporating multiple comments from above.

  1. Add strictParsing={true} to <DatePicker /> component

  2. Add custom input ref and initialize like this

    const refCustomInput = useRef<HTMLInputElement>(null)
  3. the end result should look like this in Typescript. If you use JavaScript just remove types and skip step 4.

    const [selectedDate, setSelectedDate] = useState<Date | null>(null)
    const refCustomInput = useRef<HTMLInputElement>(null)
    
    const handleDateChange = (date: Date | null) => setSelectedDate(date)
    
    const CustomInput = forwardRef<HTMLInputElement, ExampleCustomInputProps>((props, ref) => {
    return <input type="text" ref={ref} {...props} />
    })
    
    return (
    <DatePicker
      selected={selectedDate}
      onChange={handleDateChange}
      dateFormat={"dd/MM/yyyy"}
      strictParsing={true}
      customInput={<CustomInput ref={refCustomInput} placeholder={dateFormat} />}
    />
    )
  4. If you’re unsure what ExampleCustomInputProps means you can simplify replace it by using any instead. This is how to shut up TypeScript, Here’s how you can define it:

    interface ExampleCustomInputProps extends React.InputHTMLAttributes<HTMLInputElement> {
    // Any additional props specific to your custom input
    }
serudda commented 1 week ago

@hebontes I think is not working as you shared:

https://codesandbox.io/p/sandbox/react-datepicker-issue-wyunxm?file=%2Fsrc%2Findex.tsx%3A39%2C1

Zyruks commented 1 week ago

🎉 Solution for Custom Input Datepicker Bug 🛠️

Hi everyone,
I encountered the same issue and found a solution that resolves the problem with typing and deleting dates when using a custom input component.

🔍 Problem

The issue arises when a custom input component is passed to customInput inside the App function. Typing a date directly into the custom input field behaves unexpectedly, such as auto-formatting too soon or preventing proper deletion of characters.

🚀 Solution

The key to solving this issue is:

  1. Moving the CustomInput component outside the App function. This ensures that the component is not re-rendered unnecessarily.
  2. Using a separate handleDateChange function to handle the state update for the second datepicker (startDate2), which also improves performance and predictability.

💡 Explanation

By moving the CustomInput component outside the main App function, the custom input is treated as a stable component, avoiding issues caused by re-rendering. This improves typing behavior and ensures the date formatting doesn't happen prematurely or incorrectly.

Here’s a CodeSandbox example showing the solution in action.

🎥 Video

https://github.com/user-attachments/assets/1ac6c8e2-e4af-4124-b963-4098910ea364

Let me know if this helps, and feel free to ask any questions! 😄