---
title: Migrate DatePicker from Polaris React
description: >-
  Replace Polaris React DatePicker with s-date-picker or s-date-field and
  migrate Date objects to date-only ISO strings safely.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/date-picker
  md: >-
    https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/date-picker.md
api_name: app-home
---

# Migrate Date​Picker from Polaris React

Use [`s-date-picker`](https://shopify.dev/docs/api/app-home/web-components/forms/date-picker) when merchants benefit from a visible calendar. Use [`s-date-field`](https://shopify.dev/docs/api/app-home/web-components/forms/date-field) when one date belongs in a standard form.

The value model changes from JavaScript `Date` objects to date-only strings such as `2025-05-28` and range strings such as `2025-05-28--2025-05-31`.

If the app renders this controlled field through React, upgrade to React 19 first. React 18 doesn't provide the custom-element property and event behavior this example relies on. If you can't upgrade yet, leave the controlled Polaris React field in place during this migration slice.

***

## Migrate a date range

## Migrating a reporting date range

##### Polaris web components

```html
<s-date-picker
  view="2025-05"
  type="range"
  value="2025-05-28--2025-05-31"
></s-date-picker>
```

##### Polaris React

```tsx
import {DatePicker} from '@shopify/polaris';

export function ReportingRange({range, month, year, setRange, changeMonth}) {
  return (
    <DatePicker
      month={month}
      year={year}
      selected={range}
      allowRange
      disableDatesBefore={new Date(2025, 0, 1)}
      disableDatesAfter={new Date(2025, 11, 31)}
      onChange={setRange}
      onMonthChange={changeMonth}
    />
  );
}
```

***

## Replace Date​Picker properties

| Polaris React | Polaris web components | Migration notes |
| - | - | - |
| `selected` Date | `value="YYYY-MM-DD"` with `type="single"` | Store a date-only value when time isn't part of the task. |
| `selected` range | `value="start--end"` with `type="range"` | Define whether an incomplete range can submit. |
| `allowRange` | `type="range"` | The destination supports one date or one continuous range. It doesn't support an independent multi-date selection mode. |
| `month` and `year` | `view="YYYY-MM"` | Pad the month to two digits. |
| `onMonthChange(month, year)` | `onViewchange(event)` | Read `event.currentTarget.view`. |
| `onChange(range)` | `onChange(event)` | Read `event.currentTarget.value`. |
| `disableDatesBefore` and `disableDatesAfter` | `allow` or `disallow` ranges | Serialize inclusive date-only boundaries explicitly. |
| `disableSpecificDates` | Comma-separated `disallow` values | Serialize each date as `YYYY-MM-DD`. |
| `weekStartsOn` | Remove | Let the localized component own calendar conventions. |
| `multiMonth` | One responsive calendar or start/end `s-date-field` controls | Don't force two calendars into narrow embedded layouts. |
| `dayAccessibilityLabelPrefix` | Remove | The destination owns day accessibility labels. |

***

## Avoid timezone shifts

Don't call `toISOString().slice(0, 10)` on a local-midnight `Date` without checking the timezone conversion. It can produce the previous or next calendar date. Format the intended local year, month, and day directly, or migrate the domain model to a date-only type at the server boundary.

When reading the destination value, don't create a local `Date` only to store it again. Keep `YYYY-MM-DD` through validation and transport when the domain value has no time or timezone.

***

## Preserve constraints and navigation

`allow` and `disallow` accept dates, months, years, and inclusive ranges. Convert all old before, after, and specific-date rules, then test their boundaries. If the rules are calculated on the server, render the same normalized constraints that the server validates.

Use `view` only when the app must control the displayed month. Otherwise use `defaultView` and let the component own navigation. Don't update the selected date when only the calendar view changes.

***

## Choose a date field for forms

Use `s-date-field` for scheduling or settings forms where a compact labelled input is appropriate. Set `label`, `name`, `value`, `required`, `details`, and `error` on the field. For a range represented by two fields, validate that the end date isn't before the start date and put the error on the relevant field or group.

***

## Test the migration

* Select single dates and ranges, including incomplete ranges where the workflow allows them.
* For an old independent multi-date workflow, test the replacement control or redesigned task separately; don't serialize multiple dates into `s-date-picker`.
* Test before, after, specific-date, and weekday constraints at every boundary.
* Navigate months without changing the selected value.
* Load and submit dates in timezones ahead of and behind UTC, including daylight-saving transitions.
* Test incomplete ranges, form reset, validation errors, keyboard operation, and narrow layouts.

***

## Remove Polaris React

After every date workflow uses a date-only string model, remove `DatePicker`, Date-object adapters used only by the UI, and duplicated month/year state. Remove `@shopify/polaris` only after no other route in scope imports it.

***

## Related guidance

* [Date picker component](https://shopify.dev/docs/api/app-home/web-components/forms/date-picker)
* [Date field component](https://shopify.dev/docs/api/app-home/web-components/forms/date-field)
* [Migrate Form from Polaris React](https://shopify.dev/docs/apps/build/app-home/migrate-from-polaris-react/form)

***
