react-datepicker icon indicating copy to clipboard operation
react-datepicker copied to clipboard

Wrapping DatePicker in a styled-component prevents typing of dates

Open redler opened this issue 4 years ago • 7 comments

A convenient way to apply custom styling with react-datepicker is to wrap the <DatePicker /> component using the popular styled-components library. For example:

const Wrapper = styled.div`
  .react-datepicker {
    box-shadow: 3px 2px 11px rgb(0 0 0 / 30%);
  }
  .react-datepicker__input-container input {
    width: ${props.width || "auto"};
  }
`;

return (
  <Wrapper>
    <DatePicker
      onChange={date => setSelectedDate(date)}
      selected={selectedDate}
    />
  </Wrapper>
);

The Issue

Wrapping <DatePicker /> as above causes any typed entry of text that can be interpreted as a date to immediately select that date and de-focus the field — exactly as if the date had been clicked from the calendar popup. For example, typing 3 into the field will immediately populate the date 03/01/2021, instead of allowing the user to continue typing the rest of a date interactively. Typing a non-date value like - will allow the user to continue typing until a valid date is recognized. If you type ---3, you're fine until the 3, at which point the number ---3 is interpreted as the date 03/01/2021.

Wrapping <DatePicker /> in a plain <div> does not cause this problem.

Wrapping <DatePicker /> in a <Wrapper /> does cause this problem, even if the wrapper contains no styles at all.

Minimal Repro Case

...

import DatePicker from "react-datepicker";
import styled from "styled-components";

const [selectedDate, setSelectedDate] = useState(null);

const Wrapper = styled.div`
`;

return (
  <Wrapper>
    <DatePicker
      onChange={date => setSelectedDate(date)}
      selected={selectedDate}
    />
  </Wrapper>
);

The expected behavior here would be that the user is allowed to begin typing text like 4/1/2024, and the cursor would remain in the field and allow that date to continue to be typed.

The observed behavior is that the instant the 4 is typed, the field is populated and defocused. Swapping out <Wrapper> for a plain <div> allows the correct behavior again.

In all other ways, the styled wrapper approach works fine.

redler avatar Apr 01 '21 19:04 redler

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Oct 02 '21 00:10 stale[bot]

Bump. Still a problem.

redler avatar Dec 15 '21 01:12 redler

I think this is down to how you have defined your Wrapper. Styled components should be defined outside otherwise any change to state will cause them to be recreated. The typed input is changing state which recreates your Wrapper and unmounts its children.

import DatePicker from "react-datepicker";
import styled from "styled-components";

const Wrapper = styled.div``; // Moved outside of Calendar component

const Calendar = () => {
  const [selectedDate, setSelectedDate] = useState(null);

  return (
    <Wrapper>
      <DatePicker
        onChange={date => setSelectedDate(date)}
        selected={selectedDate}
      />
    </Wrapper>
  );
};

https://styled-components.com/docs/basics#define-styled-components-outside-of-the-render-method

drnare avatar Dec 21 '21 10:12 drnare

You can wrap directly the DatePicker component like :

const Wrapper = styled(DatePicker)`
    border-radius: 4px;
    border: 1px solid ${colors('grey')};
`

and use the Wrapper component instead DatePicker like

<Wrapper
    selected={startDate}
    onChange={(date) => setStartDate(date)}
/>

alimtunc avatar Jan 17 '22 15:01 alimtunc

Same for me, @redler except that in my case I've defined outside the styled components for CalendarContainer (and not the Wrapper) and, unfortunately, solution provided by @alimtunc doesn't work for me because no style rule is applied.

Polm1 avatar Mar 18 '22 12:03 Polm1

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

stale[bot] avatar Nov 02 '22 06:11 stale[bot]

If all you wan to do is style the calendar element, use the calendarContainer prop:

// Styled component
export const CalendarContainer = styled.div`
    width: 400px;
`;

// Component
export const DatePicker = () => {
    const [startDate, setStartDate] = useState(new Date());

    return (
        <ReactDatePicker
            calendarContainer={Styled.CalendarContainer}
            selected={startDate}
            onChange={(date) => setStartDate(date)}
        />
    );
};

bradlocking avatar Nov 17 '23 15:11 bradlocking

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 10 days.

github-actions[bot] avatar Jul 27 '24 01:07 github-actions[bot]

This issue was closed because it has been stalled for 10 days with no activity.

github-actions[bot] avatar Aug 06 '24 01:08 github-actions[bot]