#ClimateEmergency

Migration Guide for DateInput

The future of date entry in GDS lies in new components aptly named NewDateInput and NewDateRangeInput. The old DateInput and DateRangeInput are still available for use, but it is expected that they will be deprecated soon.

This guide will aid you in migrating your DateInput to NewDateInput and DateRangeInput to NewDateRangeInput.

Removing react-dates styles

NewDateInput and NewDateRangeInput no longer rely on react-dates. This means that once you migrate from DateInput and DateRangeInput, your app no longer needs to import react-dates styles and the following code can be removed:

jsximport 'react-dates/lib/css/_datepicker.css';

Moving away from Moment.js

GDS is also moving away from Moment.js and all NewDateInput/NewDateRangeInput APIs now use JavaScript Date objects.

To enable use cases where NewDateInput and NewDateRangeInput are used as controlled inputs, we need to be able to pass not only the parsed Date value, but also the current string values in the inputs.

In (the old) DateInput and DateRangeInput this worked thanks to Moment.js’ _i property which stores string value that failed to parse. This props is present only in invalid Moments.

We are going to do a similar thing. For invalid dates our API uses JavaScript Invalid date object with a custom attribute invalidString. The attribute is present only when the date is invalid.

HINT Converting between Moment.js and JavaScript Date objects right at the border of our API lets you continue using Moment.js as long as you want. Once you are ready to move on, you may choose any date library you want to use. We personally chose date-fns and had a pleasant experience 🤗.

Callbacks

The following functions are called with JavaScript Date objects:

  • NewDateInput’s onDateChange
  • NewDateRangeInput’s onDatesChange

For easy upgrade you may convert the incoming values to Moment right away.

jsxconst nativeDateToMoment = (nativeDate) => {
  const momentDate = moment(nativeDate);

  if (nativeDate.invalidString) {
    momentDate._i = nativeDate.invalidString;
  }

  return momentDate;
};

const handleDateChange = (nativeDate) => {
  const date = nativeDateToMoment(nativeDate);
  // …
};

const handleDatesChange = (nativeDates) => {
  const startDate = nativeDateToMoment(nativeDates.startDate);
  const endDate = nativeDateToMoment(nativeDates.endDate);
  // …
};

return (
  <>
    <NewDateInput onDateChange={handleDateChange} />
    <NewDateRangeInput onDatesChange={handleDatesChange} />
  </>
);

Simple props

The following props expect Date objects:

  • NewDateInput’s date
  • NewDateRangeInput’s startDate and endDate

For easy upgrade you may convert your Moment objects to Date objects right before passing them.

jsxconst momentToNativeDate = (momentDate) => {
  const nativeDate = momentDate.toDate();

  if (momentDate._i) {
    nativeDate.invalidString = momentDate._i;
  }

  return nativeDate;
};

const date = moment('2021-08-01'); // variables used in
const anotherDate = moment('2021-08-10'); // your app previously

const nativeDate = momentToNativeDate(date);
const anotherNativeDate = momentToNativeDate(anotherDate);

return (
  <>
    <NewDateInput date={nativeDate} />
    <NewDateRangeInput startDate={nativeDate} endDate={anotherNativeDate} />
  </>
);

isOutsideRange

The isOutsideRange prop supported in both NewDateInput and NewDateRangeInput expects a function accepting a JavaScript Date object.

For easy upgrade you may convert the value to Moment at the beginning or you may choose to get rid of Moment in these functions altogether.

jsx<NewDateInput isOutsideRange={(date) => moment(date).isAfter(moment('2021-05-15'))} />

As before, the default outside range is set to past dates, so the NewDateInput and NewDateRangeInput disables the dates before today. All dates can be enabled the same way as before.

jsx<NewDateInput isOutsideRange={() => false} />

Change of defaults

NewDateInput and NewDateRangeInput default to showClearDate being true. To prevent rendering clear date button in case it is specifically requested to stay hidden set it to false.

jsx<NewDateInput showClearDate={false} />
<NewDateRangeInput showClearDate={false} />

The default placeholders were removed. If you want to keep them, you need to add them.

jsxconst format = "DD.MM.YYYY";

<NewDateInput placeholder={format} />
<NewDateRangeInput
  placeholderStart={format}
  placeholderEnd={format}
/>

Unicode tokens

The new components use standard Unicode tokens for formatting instead of the tokens used by Moment.js.

This concerns the following props of both NewDateInput and NewDateRangeInput.

  • displayFormat
  • weekDayFormat
  • monthFormat

Some key differences:

  • D and DD are now d and dd when denoting day of a month
  • YY and YYYY are now yy and yyyy when denoting a year
jsx// Before:

<DateInput displayFormat="DD.MM.YYYY" />

// After:

<NewDateInput displayFormat="dd.MM.yyyy" />

HINT This is also why we no longer default to using displayFormat as a placeholder since it would be partially lowercase.

Since parsing is handled within GDS, there is no change regarding the parsing tokens required on your side.

Language strings

There are new language strings which should be added – input.date.previousMonth and input.date.nextMonth.