Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Datepicker is generating TextInput contains an input of type text with both value and defaultValue #1511

Open
2 tasks done
zulander1 opened this issue Nov 20, 2024 · 8 comments

Comments

@zulander1
Copy link

zulander1 commented Nov 20, 2024

  • I have searched the Issues to see if this bug has already been reported
  • I have tested the latest version

I am initializing the Datepicker to be empty, however, I am getting a warning on the console with: _TextInput contains an input of type text with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both).

const [selectedDate, setselectedDate] = useState<Date | null>(null);
<Datepicker className="datepicker-buttons w-full" value={selectedDate} label=""></Datepicker>

Changing the label to =" " make the warning go away

@monikacil
Copy link

I've got the same issue, is there any possible way to avoid that error occurency?
In my case it's appear only during first render.
Changing the label to =" " didn't help.

Context
Nextjs project running locally and testing on Chrome 131.0.6778.109.

@SutuSebastian
Copy link
Collaborator

@rluders

@MiroslavPetrik
Copy link
Contributor

MiroslavPetrik commented Jan 27, 2025

Yeah, its broken.

Image

Also, onChange does not work for me at all, I cannot get the value out hmm.
Edit: the controlled example in docs is not showing...
https://flowbite-react.com/docs/components/datepicker#controlled-datedatepicker

Does the onChange work for somebody?

@MuellerConstantin
Copy link

It's still broken, I observed a similar behavior... Depending on which options you're using (e.g. value, onChange, defaultValue, label) the behavior is slightly different, but it leads always to unwanted side effects.

Initial Situation

First, sorry for the long text, but that's the detailed analysis. As far as I can tell, I'm happy to disagree, but that's the problem. Basically, the component works even as controlled input, meaning the state can be controlled with value and onChange. However, warnings still occur.

// Test.tsx

import { useState } from "react";
import { Datepicker } from "flowbite-react";

export default function Test() {
  const [date, setDate] = useState<Date | null>(null);

  return (
    <form>
      <Datepicker
        value={date}
        onChange={(newDate) => setDate(newDate)}
        placeholder="Select date"
      />
    </form>
  );
}

In this scenario we have a controlled component (See Controlled Date/Datepicker.) and no date should be selected by default, hence the selected value should be null. At first glance, it seems to work. The internally used text field component is empty and instead the placeholder is shown. But when you select a date using the picker, a warning is thrown.

First Warning

Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://reactjs.org/link/controlled-components

The reason for this seems to be that the value for the internal text field is recalculated internally (See Datepicker.tsx:261). If value is null, which is the case, then label is used as value of the internal text field component. But label is undefined, an in consequence the warning is thrown after selecting a date (Switching from undefined to defined). FYI: label seems to be used as some kind of placeholder here, but I don't understand why it doesn't use the placeholder property instead.

// Datepicker.tsx

const displayValue = value === null ? label : getFormattedDate(language, selectedDate || new Date());

...

<TextInput
  ...
  value={displayValue}
/>

Anyways, if you decide to add the label property (e.g. label="Select date") it still seem to work technically and it resolves the former error but it also results in a new one.

Aftereffect

Warning: TextInput contains an input of type text with both value and defaultValue props. Input elements must be either controlled or uncontrolled (specify either the value prop, or the defaultValue prop, but not both). Decide between using a controlled or uncontrolled input element and remove one of these props. More info: https://reactjs.org/link/controlled-components

The reason here is that the component internally calculates the initialDate based on the defaultValue (Not provided, hence undefined). In case of defaultValue is undefined, which is the case, initialDate becomes null (See Datepicker.tsx:129). initialDate is later used to set the internal text field's defaultValue field, which becomes the the label's value in case that initialDate is null (See Datepicker.tsx:296), which is the case. Because we have set label to "Select date", defaultValue is obviously set (!= undefined) at the same time as value is and that leads to the aftereffect.

// Datepicker.tsx

const initialDate = defaultValue ? getFirstDateInRange(defaultValue, minDate, maxDate) : null;

...

<TextInput
  ...
  defaultValue={initialDate ? getFormattedDate(language, initialDate) : label}
/>

PS: I would also be willing to fix the issue myself or rewrite the code once the solution has been discussed.

@SutuSebastian
Copy link
Collaborator

SutuSebastian commented Mar 21, 2025

@MuellerConstantin that's a very thorough breakdown of the issue, thank u!

The next chapter after the #1498 is merged, is to start thinking of really good headless component library we can use, tbh I am really tired of the issues a complex component like Datepicker can have, and yet it wasn't properly discussed nor implemented from the beginning.

So I say and suggest that Datepicker component is a lost cause and shall be entirely replaced by something more robust, such as: React Aria (DatePicker) or Base UI (not yet implemented).

@MuellerConstantin
Copy link

@SutuSebastian Is this a final decision? Because in my opinion it shouldn't be that hard to address this issue, I would address it myself. Of course, I don't know if there are other problems with the component that are more difficult to fix.

@MiroslavPetrik
Copy link
Contributor

@SutuSebastian I reached the same conclusion and went with react-day-picker.
It is standalone which makes it perfect for integrating in any UI library. It has fully customizable styles or components.

@SutuSebastian
Copy link
Collaborator

SutuSebastian commented Mar 24, 2025

@SutuSebastian Is this a final decision? Because in my opinion it shouldn't be that hard to address this issue, I would address it myself. Of course, I don't know if there are other problems with the component that are more difficult to fix.

Going headless for really complex components it's for sure, that is why I'm suggesting not to spend a serious amount of time on this, because any fixes brought to this component will only live until the headless approach is implemented.

Feel free to contribute with a fix to this at ur own pace 🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants