Components

customdatetimepicker

A combined date-and-time picker. Use when a single field must capture both a calendar date and a time of day.

A combined date-and-time picker. Use when a single field must capture both a calendar date and a time of day.

Read Form Rules before using this component — keys, labels, required fields, expressions, visibility, and validation all follow shared conventions.

When to use

  • Appointment date and time
  • Submission deadlines that include a cut-off time
  • Event start time, interview slot, or any other moment-in-time value
  • Booking slots constrained by both calendar restrictions and working hours

When NOT to use

Instead of customdatetimepicker, use…For…
customdatepickerA calendar date only, with no time component
customtimepickerA time of day only, with no associated date
Two separate fieldsCapturing a date range — use one picker per endpoint

Props

PropTypeRequired?Description
labelstringrequiredVisible label. Must be unique across the form.
requiredbooleanrequiredAlways false. The expression controls the runtime value.
defaultRequiredbooleanrequiredtrue for required fields, false for optional ones.
placeholderstringoptionalGhost text shown before a value is selected. Default "Select Date".
minDateobjectoptionalEarliest selectable date as { "year": N, "month": N, "day": N }. Not a string or ISO date. Default { year: 1900, month: 1, day: 1 }.
maxDateobjectoptionalLatest selectable date as { "year": N, "month": N, "day": N }. Not a string or ISO date. Default currentYear + 10.
addRemoveTimeMinDatestringoptionalRuntime offset applied to minDate. Format: "N:d" where N is days (negative = past, positive = future). e.g. "0:d" = today, "-2:d" = 2 days ago.
addRemoveTimeMaxDatestringoptionalRuntime offset applied to maxDate. Same format as addRemoveTimeMinDate.
allowedDaysOfTheWeeknumber[]optionalDays the user may select. Omit to allow all days.
startHournumberoptionalEarliest selectable hour in 24h format. Default 8.
endHournumberoptionalLatest selectable hour in 24h format. Default 16.
intervalnumberoptionalMinute interval between time slots. Default 30.
dateFormatstringoptionalDisplay format, e.g. "DD MM YYYY". Default "DD MM YYYY".
delimeterstringoptionalDate part separator, e.g. "/", "-". Default "-".
eventCodestringoptionalEvent code for loading restricted/available dates from the backend.
eventDatesMaxSizestringoptionalMaximum number of event dates to load. Must be a string, e.g. "5".
tooltipstringoptionalHelp text shown as an icon tooltip next to the label.
hintstringoptionalHelp text rendered below the field, always visible.
hideFieldbooleanoptionalHides the field and excludes its value from submission. Toggle via expressions["props.hideField"].
classNamestringoptionalCSS class applied to the field wrapper.

The required mechanism

Every customdatetimepicker field must include this exact expression, regardless of whether the field is required or optional.

"expressions": {
  "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
}
  • To make a field required: set defaultRequired: true.
  • To make a field optional: set defaultRequired: false.

Examples

Minimal — optional date-time

{
  "key": "APPOINTMENT_DATE_TIME",
  "type": "customdatetimepicker",
  "props": {
    "label": "Appointment Date and Time",
    "required": false,
    "defaultRequired": false
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {}
  }
}

Required date-time field

{
  "key": "APPOINTMENT_DATE_TIME",
  "type": "customdatetimepicker",
  "props": {
    "label": "Appointment Date and Time",
    "placeholder": "Select date and time",
    "required": false,
    "defaultRequired": true
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "Appointment Date and Time is required."
    }
  }
}

Full example — weekday slots inside working hours, from tomorrow onwards

{
  "key": "APPOINTMENT_DATE_TIME",
  "type": "customdatetimepicker",
  "props": {
    "label": "Appointment Date and Time",
    "placeholder": "Select date and time",
    "required": false,
    "defaultRequired": true,
    "minDate": { "year": 2024, "month": 1, "day": 1 },
    "addRemoveTimeMinDate": "1:d",
    "allowedDaysOfTheWeek": [1, 2, 3, 4, 5],
    "startHour": 8,
    "endHour": 17,
    "interval": 30,
    "dateFormat": "DD MM YYYY",
    "delimeter": "-"
  },
  "expressions": {
    "props.required": "!(field?.props?.hideField || field?.hide) && field?.props?.defaultRequired"
  },
  "validation": {
    "messages": {
      "required": "Appointment Date and Time is required."
    }
  }
}

Common mistakes

  • Using customdatetimepicker when only a date is needed — use customdatepicker instead.
  • Using customdatetimepicker when only a time is needed — use customtimepicker instead.
  • Setting props.required: true directly — always use defaultRequired: true with the standard expression.
  • Using validators: { validation: [...] } instead of validation: { messages: {} } for required messages.
  • Setting allowedDaysOfTheWeek with day names (e.g. "Monday") — it must be an array of numbers.
  • Setting startHour/endHour/interval as strings — they must be numbers.
  • Setting minDate/maxDate as ISO strings — they must be { "year": N, "month": N, "day": N } objects.

Checklist

  • key is UPPER_SNAKE_CASE and unique across the entire form
  • props.label is present, unique, and correctly cased
  • Field is nested at the correct depth: sections > formly-group > block > customdatetimepicker
  • required: false is set (never true)
  • defaultRequired is set
  • expressions["props.required"] is present with the exact required expression
  • validation.messages.required is present when defaultRequired: true
  • minDate/maxDate, if used, are objects not strings
  • addRemoveTimeMinDate/addRemoveTimeMaxDate, if used, are "N:d" strings not numbers
  • allowedDaysOfTheWeek, if used, is an array of integers
  • startHour, endHour, and interval are numbers, not strings

On this page