shadcn-ui / ui

Beautifully designed components that you can copy and paste into your apps. Accessible. Customizable. Open Source.
https://ui.shadcn.com
MIT License
61.69k stars 3.48k forks source link

Date Range Picker incorrect behaviour #715

Closed tanvirbhachu closed 4 days ago

tanvirbhachu commented 1 year ago

I would like to report a minor issue with the date range picker functionality. Currently, there is a small behavior problem that I have noticed.

Here's how it works: Suppose you select the date range from the 16th of June to the 24th of June. It works perfectly fine and functions as expected. However, if you try to change the start date, you will encounter a problem. The start date does not reset properly, making it difficult to select a new start date. For instance, you can select the 14th of June as the start date, but you cannot select the 20th of June.

To select the 20th of June as the new start date, you have to double click on it. Unfortunately, this behavior is not intuitive and does not align with what users would expect.

In React Aria and Mantine, if the start and end dates have already been selected, the next selection should be treated as the new start date.

Shadcn Range Picker Mantine Range Picker Styled example using React Aria's useRangeCalendar

tony-matheus commented 12 months ago

@TimTan1200 If I'm not mistaken, the behaviour you're referring to is related to the React DayPicker. Switching to Mantine might resolve the issue you mentioned. However, I'd like to hear your opinion on the behaviour of Google Flights.

In Google Flights, when you click for the first time, it selects the start_date, and the second click selects the end_date. If you click again, it switches back to selecting the start_date, and the subsequent click switches back to end_date. This toggling behaviour continues until you reset the selection.

tanvirbhachu commented 11 months ago

Yup, that's precisely what I'd like since that's the common behaviour across pretty much all websites I interact with.

jerodfritz commented 11 months ago

I agree the current behavior is confusing. I would describe the issue as :

A user is only able to select a start date that is previous to the currently selected start date. There is no way for the user to select a start date after the currently selected start date.

jerodfritz commented 11 months ago

Also fwiw, by adding a min={2} parameter on Calendar solves the UX for me

      <Calendar
        initialFocus
        mode="range"
        defaultMonth={dateBegin ? dateBegin : new Date()}
        selected={{ from: dateBegin, to: dateEnd }}
        onSelect={handleSelect}
        numberOfMonths={4}
        min={2}
      />

I agree the current behavior is confusing. I would describe the issue as :

A user is only able to select a start date that is previous to the currently selected start date. There is no way for the user to select a start date after the currently selected start date.

devarapalli-ojas commented 8 months ago

I have noticed another strange behaviour. When I select start date it is perfect, but end date automatically choosing the present day (today). But if we refresh next time it is considering the input values correctly.

donalffons commented 4 months ago

The react daypicker docs mention how to configure the selection behavior.

Starting from the Date Range Picker example in shadcn, I made this tiny modification to get the desired behavior:

<Calendar
  initialFocus
  mode="range"
  defaultMonth={date?.from}
  selected={date}
  onDayClick={(day) => setDate((prev) => (prev?.to ? { from: day, to: undefined } : prev?.from ? { from: prev?.from, to: day } : { from: day, to: undefined }))}
  numberOfMonths={2}
  weekStartsOn={1}
/>
agomesd commented 1 month ago

The react daypicker docs mention how to configure the selection behavior.

Starting from the Date Range Picker example in shadcn, I made this tiny modification to get the desired behavior:

<Calendar
  initialFocus
  mode="range"
  defaultMonth={date?.from}
  selected={date}
  onDayClick={(day) => setDate((prev) => (prev?.to ? { from: day, to: undefined } : prev?.from ? { from: prev?.from, to: day } : { from: day, to: undefined }))}
  numberOfMonths={2}
  weekStartsOn={1}
/>

This doesn't handle the case where you pick an initial date, then pick a date in the past => This will give a you a negative range.

I've modified to handle this case:

const handleDayClick = (day: Date) => {
    setDateRange((prev) => {
      if (prev?.to) {
        // If 'to' is already set, reset the range
        return { from: day, to: undefined };
      } else if (prev?.from) {
        // If 'from' is set and 'to' is not
        if (day < prev.from) {
          // If the new day is before the 'from' date, reset the range
          return { from: day, to: undefined };
        } else {
          // Otherwise, set the 'to' date
          return { from: prev.from, to: day };
        }
      } else {
        // If neither 'from' nor 'to' is set, set 'from'
        return { from: day, to: undefined };
      }
    });
shadcn commented 4 days ago

This issue has been automatically closed because it received no activity for a while. If you think it was closed by accident, please leave a comment. Thank you.