---
title: Date Picker
product: Form Library
description: Learn how to integrate a third-party date picker as a custom SurveyJS question type in React, Angular, and Vue applications.
framework: React
source: https://surveyjs.io/form-library/examples/form-with-datepicker/reactjs
index: https://surveyjs.io/form-library/examples/overview.md
---

# Date Picker (React)

A date picker allows respondents to select a date using a calendar popup or by entering a value manually in an input field. This example demonstrates how to integrate a third-party date picker as a custom SurveyJS question type. Each platform uses a different MIT-licensed date picker component: <a href="https://github.com/Hacker0x01/react-datepicker#react-date-picker" target="_blank">React Date Picker</a>, <a href="https://material.angular.io/components/datepicker" target="_blank">Angular Material Datepicker</a>, or <a href="https://vue3datepicker.com/" target="_blank">Vue Datepicker</a>.

Despite using different libraries, all three implementations share the same question model and behavior, so a single survey JSON definition works across platforms without modification. The integration approach follows the common pattern described in the Form Library tutorials linked at the end of this page.

This demo defines a custom question type that:

- Renders a third-party date picker inside a SurveyJS form
- Supports configuration of display format, placeholder, minimum/maximum selectable dates, and clearing behavior
- Stores the selected value as a normalized `yyyy-MM-dd` string in survey results (for example, `2026-06-08`)

## Survey JSON

```js
{
  "elements": [
    {
      "type": "third-party-datepicker",
      "name": "deliveryDate",
      "title": "Preferred delivery date",
      "isRequired": true,
      "dateFormat": "MM/dd/yyyy",
      "placeholder": "Select a date",
      "allowClear": true,
      "minDate": "2026-06-01",
      "maxDate": "2026-12-31"
    }
  ]
}
```

After completion, the resulting data contains:

```js
{
  "deliveryDate": "2026-06-08"
}
```

The display format (`MM/dd/yyyy` &rarr; `06/08/2026`) affects only how the value is shown in the UI; it does not affect the stored data format.

## Custom Question Properties

The date picker extends the standard [`Question`](/form-library/documentation/api-reference/question) class with the following properties:

| Property | Type | Default | Description |
| -------- | ---- | ------- | ----------- |
| `dateFormat` | `string` | `"MM/dd/yyyy"` | Controls how the date is displayed in the input using <a href="https://date-fns.org/docs/format" target="_blank">date-fns tokens</a>. Not applicable in Angular (see note below). |
| `placeholder` | `string` | `""` | Placeholder text shown when no date is selected. |
| `allowClear` | `boolean` | `true` | Enables clearing the selected date. When disabled, the value can only be changed via the calendar UI. |
| `minDate` | `string` | `""` | Minimum selectable date in `yyyy-MM-dd` format. Empty means no lower bound. |
| `maxDate` | `string` | `""` | Maximum selectable date in `yyyy-MM-dd` format. Empty means no upper bound. |

> Angular Material does not support per-control format strings. Date display is configured globally via the <a href="https://material.angular.io/components/datepicker/overview#customizing-the-parse-and-display-formats" target="_blank">MAT_DATE_FORMATS</a> injection token. The Angular demo uses a global format matching `MM/dd/yyyy` (e.g., `06/08/2026`) and ignores the `dateFormat` property. To change formatting, update the `DATEPICKER_DATE_FORMATS` constant in the Angular implementation.

## Integration Tutorials

For step-by-step instructions on integrating third-party components (model definition, serialization, rendering, and registration), see:

- [Integrate Third-Party React Components](https://surveyjs.io/form-library/documentation/customize-question-types/third-party-component-integration-react)
- [Integrate Third-Party Angular Components](https://surveyjs.io/form-library/documentation/customize-question-types/third-party-component-integration-angular)
- [Integrate Third-Party Vue 3 Components](/form-library/documentation/customize-question-types/third-party-component-integration-vue)

## Files

### `public/index.html`

```html
<div id="surveyElement" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; min-height: 100%; height:100%"></div>
```

### `src/Datepicker.css`

```css
.sd-text__content.sd-datepicker .react-datepicker-wrapper {
  width: 100%;
}

/* Show the calendar popup above SurveyJS elements. */
.react-datepicker-popper,
#sd-datepicker-portal {
  position: relative;
  z-index: 11000;
}

/* Reserve room for the clear button so the date text does not run under it. */
.sd-text__content.sd-datepicker .react-datepicker-wrapper .sd-datepicker__input {
  padding-inline-end: 40px;
}

/* Restyle the clear button to match the SurveyJS Dropdown clean button. */
.sd-text__content.sd-datepicker .sd-datepicker__clear-button {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  cursor: pointer;
}

.sd-text__content.sd-datepicker .sd-datepicker__clear-button::after {
  content: "";
  display: block;
  width: 24px;
  height: 24px;
  padding: 0;
  border-radius: 0;
  background-color: var(--sjs-general-forecolor-light, rgba(0, 0, 0, 0.45));
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z'/%3E%3C/svg%3E") center / 16px 16px no-repeat;
}

.sd-text__content.sd-datepicker .sd-datepicker__clear-button:hover::after {
  background-color: var(--sjs-general-forecolor, rgba(0, 0, 0, 0.91));
}
```

### `src/DatepickerComponent.jsx`

```js
import { createElement } from 'react';
import DatePicker from 'react-datepicker';
import { ElementFactory, Question, Serializer } from 'survey-core';
import { ReactQuestionFactory, SurveyQuestionElementBase } from 'survey-react-ui';
import 'react-datepicker/dist/react-datepicker.css';
import './Datepicker.css';

const CUSTOM_TYPE = 'third-party-datepicker';

let registered = false;

export class QuestionDatepickerModel extends Question {
  getType() {
    return CUSTOM_TYPE;
  }

  get dateFormat() {
    return this.getPropertyValue('dateFormat') || 'MM/dd/yyyy';
  }
  set dateFormat(val) {
    this.setPropertyValue('dateFormat', val);
  }

  get placeholder() {
    return this.getPropertyValue('placeholder') ?? '';
  }
  set placeholder(val) {
    this.setPropertyValue('placeholder', val);
  }

  get allowClear() {
    return this.getPropertyValue('allowClear') !== false;
  }
  set allowClear(val) {
    this.setPropertyValue('allowClear', val);
  }

  get minDate() {
    return this.getPropertyValue('minDate') ?? '';
  }
  set minDate(val) {
    this.setPropertyValue('minDate', val);
  }

  get maxDate() {
    return this.getPropertyValue('maxDate') ?? '';
  }
  set maxDate(val) {
    this.setPropertyValue('maxDate', val);
  }
}

function toISODateString(d) {
  const y = d.getFullYear();
  const m = String(d.getMonth() + 1).padStart(2, '0');
  const day = String(d.getDate()).padStart(2, '0');
  return `${y}-${m}-${day}`;
}

function parseISODate(s) {
  if (s == null || s === '') return null;
  if (s instanceof Date && !isNaN(s.getTime())) return s;
  if (typeof s !== 'string') return null;
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s.trim());
  if (!m) return null;
  const dt = new Date(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
  return isNaN(dt.getTime()) ? null : dt;
}

export class SurveyQuestionDatepicker extends SurveyQuestionElementBase {
  get question() {
    return this.questionBase;
  }

  get wrapperStyle() {
    return this.question.isInputReadOnly || this.question.isDesignMode
      ? { pointerEvents: 'none', opacity: 0.85 }
      : {};
  }

  inputClassName() {
    const q = this.question;
    const parts = ['sd-input', 'sd-datepicker__input'];
    if (q.isInputReadOnly) {
      parts.push('sd-input--readonly', 'sd-input--disabled');
    }
    if (q.currentErrorCount > 0) {
      parts.push('sd-input--error');
    }
    return parts.join(' ');
  }

  renderElement() {
    const question = this.question;
    return (
      <div className="sd-text__content sd-datepicker" style={this.wrapperStyle}>
        <DatePicker
          selected={parseISODate(question.value)}
          onChange={(date) => {
            question.value = date ? toISODateString(date) : null;
          }}
          dateFormat={question.dateFormat}
          placeholder={question.placeholder}
          allowClear={question.allowClear && !question.isInputReadOnly}
          minDate={parseISODate(question.minDate) || undefined}
          maxDate={parseISODate(question.maxDate) || undefined}
          disabled={question.isInputReadOnly}
          id={question.inputId}
          className={this.inputClassName()}
          clearButtonClassName="sd-datepicker__clear-button"
          wrapperClassName="sd-datepicker__wrapper"
          portalId="sd-datepicker-portal"
          autoComplete="off"
        />
      </div>
    );
  }
}

if (!registered) {
  registered = true;

  ElementFactory.Instance.registerElement(CUSTOM_TYPE, (name) => {
    return new QuestionDatepickerModel(name);
  });

  Serializer.addClass(
    CUSTOM_TYPE,
    [
      {
        name: 'dateFormat',
        type: 'string',
        default: 'MM/dd/yyyy',
        category: 'general',
        visibleIndex: 2,
      },
      {
        name: 'placeholder',
        type: 'string',
        default: '',
        category: 'general',
        visibleIndex: 3,
      },
      {
        name: 'allowClear',
        type: 'boolean',
        default: true,
        category: 'general',
        visibleIndex: 4,
      },
      {
        name: 'minDate',
        type: 'string',
        default: '',
        category: 'general',
        visibleIndex: 5,
      },
      {
        name: 'maxDate',
        type: 'string',
        default: '',
        category: 'general',
        visibleIndex: 6,
      },
    ],
    () => new QuestionDatepickerModel(''),
    'question'
  );

  ReactQuestionFactory.Instance.registerQuestion(CUSTOM_TYPE, (props) =>
    createElement(SurveyQuestionDatepicker, props)
  );
}
```

### `src/SurveyComponent.jsx`

```js
import React from "react";
import { Model } from "survey-core";
import { Survey } from "survey-react-ui";
import "survey-core/survey-core.min.css";
import "./index.css";
import { json } from "./json";
import { SurveyQuestionDatepicker } from "./DatepickerComponent";


function SurveyComponent() {
    const survey = new Model(json);
    survey.onComplete.add((sender, options) => {
        console.log(JSON.stringify(sender.data, null, 3));
    });
    return (<Survey model={survey} />);
}

export default SurveyComponent;
```

### `src/index.css`

```css
.sd-text__content.sd-datepicker {
  width: 100%;
}

.sd-text__content.sd-datepicker .sd-datepicker__input {
  width: 100%;
}
```

### `src/index.js`

```js
import React from "react";
import { createRoot } from "react-dom/client";
import SurveyComponent from "./SurveyComponent";

const root = createRoot(document.getElementById("surveyElement"));
root.render(<SurveyComponent />);
```

### `src/json.js`

```js
export const json = {
  "elements": [
    {
      "type": "third-party-datepicker",
      "name": "deliveryDate",
      "title": "Preferred delivery date",
      "isRequired": true,
      "dateFormat": "MM/dd/yyyy",
      "placeholder": "Select a date",
      "allowClear": true,
      "minDate": "2026-06-01",
      "maxDate": "2026-12-31"
    }
  ]
}
;
```

### `package.json`

```json
{
  "dependencies": {
    "react": "latest",
    "react-dom": "latest",
    "react-datepicker": "^9.1.0",
    
    "survey-core": "latest",
    "survey-react-ui": "latest"
  },
  "devDependencies": {
    "react-scripts": "latest"
  }
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/form-library/examples/form-with-datepicker/angular.md)
- [Vue 3](https://surveyjs.io/form-library/examples/form-with-datepicker/vue3js.md)
