---
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: Vue 3
source: https://surveyjs.io/form-library/examples/form-with-datepicker/vue3js
index: https://surveyjs.io/form-library/examples/overview.md
---

# Date Picker (Vue 3)

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="app" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; height:100%"></div>
```

### `src/Datepicker.vue`

```html
<script setup lang="ts">
import { computed, ref } from "vue";
import { VueDatePicker } from "@vuepic/vue-datepicker";
import { useQuestion } from "survey-vue3-ui";
import "@vuepic/vue-datepicker/dist/main.css";
import { QuestionDatepickerModel } from "./DatepickerModel";

defineOptions({ inheritAttrs: false });

const props = defineProps<{ question: QuestionDatepickerModel }>();
const root = ref<HTMLElement | null>(null);

useQuestion(props, root);

// `model-type="yyyy-MM-dd"` makes the picker work with the same
// normalized date string that the question stores in survey results.
const dateValue = computed<string | null>({
  get: () => props.question.value ?? null,
  set: (val) => {
    props.question.value = val || null;
  }
});

const wrapperStyle = computed(() =>
  props.question.isInputReadOnly || props.question.isDesignMode
    ? { pointerEvents: "none" as const, opacity: "0.85" }
    : {}
);

const inputClassName = computed(() => {
  const parts = ["sd-input", "sd-datepicker__input"];
  if (props.question.isInputReadOnly) {
    parts.push("sd-input--readonly", "sd-input--disabled");
  }
  if (props.question.currentErrorCount > 0) {
    parts.push("sd-input--error");
  }
  return parts.join(" ");
});
</script>

<template>
  <div
    ref="root"
    class="sd-text__content sd-datepicker"
    :style="wrapperStyle"
    @pointerdown.stop
  >
    <VueDatePicker
      v-model="dateValue"
      model-type="yyyy-MM-dd"
      :formats="{ input: question.dateFormat }"
      :placeholder="question.placeholder"
      :clearable="question.allowClear"
      :min-date="question.minDate || undefined"
      :max-date="question.maxDate || undefined"
      :time-picker="false"
      :time-config="{ enableTimePicker: false }"
      :disabled="question.isInputReadOnly"
      :input-class-name="inputClassName"
      :teleport="true"
      auto-apply
    />
  </div>
</template>

<!-- Unscoped: the calendar menu is teleported to <body>. -->
<style>
.sd-text__content.sd-datepicker .dp__main {
  width: 100%;
}

/* Show the calendar popup above SurveyJS elements. */
.dp__menu {
  z-index: 11000 !important;
}
</style>
```

### `src/DatepickerModel.ts`

```ts
import { ElementFactory, Question, Serializer, settings } from "survey-core";

export const DATEPICKER_TYPE = "third-party-datepicker";

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

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

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

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

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

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

ElementFactory.Instance.registerElement(
  DATEPICKER_TYPE,
  (name) => new QuestionDatepickerModel(name)
);

Serializer.addClass(
  DATEPICKER_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"
);

(settings.customIcons as Record<string, string>)["icon-" + DATEPICKER_TYPE] = "icon-date";
```

### `src/App.vue`

```html
<template>
    <SurveyComponent :model="survey" />
</template>
<script setup lang="ts">
    import { Model } from "survey-core";
    import { SurveyComponent } from "survey-vue3-ui";
    import "survey-core/survey-core.min.css";
    import "./index.css";
    import { json } from "./json";

    const survey = new Model(json);
    survey.onComplete.add((sender, options) => {
        console.log(JSON.stringify(sender.data, null, 3));
    });
</script>
```

### `src/index.css`

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

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

### `src/json.ts`

```ts
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"
    }
  ]
}
;
```

### `src/main.ts`

```ts
import { createApp } from "vue";
import App from "./App.vue";
import { surveyPlugin } from "survey-vue3-ui";
import "@vuepic/vue-datepicker/dist/main.css";
import "./DatepickerModel";
import Datepicker from "./Datepicker.vue";


const app = createApp(App);
app.use(surveyPlugin);
app.component("survey-third-party-datepicker", Datepicker);

app.mount("#app");
```

### `src/shims-vue.d.ts`

```ts
/* eslint-disable */
declare module "*.vue" {
    import type { DefineComponent } from "vue"
    const component: DefineComponent<{}, {}, any>
    export default component
}
```

### `.eslintrc.js`

```js
module.exports = {
    root: true,
    env: {
        node: true
    },
    extends: [
        "plugin:vue/vue3-essential",
        "eslint:recommended",
        "@vue/typescript/recommended",
        "@vue/prettier",
        "@vue/prettier/@typescript-eslint"
    ],
    parserOptions: {
        ecmaVersion: 2020
    },
    rules: {
        "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
        "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
    },
    overrides: [
        {
            files: [
                "**/__tests__/*.{j,t}s?(x)",
                "**/tests/unit/**/*.spec.{j,t}s?(x)"
            ],
            env: {
                jest: true
            }
        }
    ]
};
```

### `babel.config.js`

```js
module.exports = {
  presets: ["@vue/cli-plugin-babel/preset"]
};
```

### `package.json`

```json
{
  "name": "surveyjs-library-vue3",
  "version": "0.1.0",
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "core-js": "^3.6.5",
    "tslib": "2.6.1",
    "vue": "^3.4.1",
    "@vuepic/vue-datepicker": "^14.0.0",
    
    "survey-core": "latest",
    "survey-vue3-ui": "latest",
    "vue-router": "^4.0.0-0",
    "vuex": "^4.0.0-0"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^2.33.0",
    "@typescript-eslint/parser": "^2.33.0",
    "@vue/cli-plugin-babel": "~4.5.0",
    "@vue/cli-plugin-eslint": "~4.5.0",
    "@vue/cli-plugin-pwa": "~4.5.0",
    "@vue/cli-plugin-router": "~4.5.0",
    "@vue/cli-plugin-typescript": "~4.5.0",
    "@vue/cli-plugin-vuex": "~4.5.0",
    "@vue/cli-service": "~4.5.0",
    "@vue/compiler-sfc": "^3.0.0",
    "@vue/eslint-config-prettier": "^6.0.0",
    "@vue/eslint-config-typescript": "^5.0.2",
    "@vue/test-utils": "^2.0.0-0",
    "eslint": "^6.7.2",
    "eslint-plugin-prettier": "^3.1.3",
    "eslint-plugin-vue": "^7.0.0-0",
    "node-sass": "^4.12.0",
    "prettier": "^1.19.1",
    "sass-loader": "^8.0.2",
    "typescript": "~3.9.3"
  }
}
```

### `tsconfig.json`

```json
{
  "compilerOptions": {
    "target": "esnext",
    "module": "esnext",
    "strict": true,
    "jsx": "preserve",
    "importHelpers": true,
    "moduleResolution": "node",
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "sourceMap": true,
    "baseUrl": ".",
    "types": [
      "webpack-env",
      "jest"
    ],
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  },
  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}
```

## Other Frameworks

- [Angular](https://surveyjs.io/form-library/examples/form-with-datepicker/angular.md)
- [React](https://surveyjs.io/form-library/examples/form-with-datepicker/reactjs.md)
