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… |
|---|---|
customdatepicker | A calendar date only, with no time component |
customtimepicker | A time of day only, with no associated date |
| Two separate fields | Capturing a date range — use one picker per endpoint |
Props
| Prop | Type | Required? | Description |
|---|---|---|---|
label | string | required | Visible label. Must be unique across the form. |
required | boolean | required | Always false. The expression controls the runtime value. |
defaultRequired | boolean | required | true for required fields, false for optional ones. |
placeholder | string | optional | Ghost text shown before a value is selected. Default "Select Date". |
minDate | object | optional | Earliest selectable date as { "year": N, "month": N, "day": N }. Not a string or ISO date. Default { year: 1900, month: 1, day: 1 }. |
maxDate | object | optional | Latest selectable date as { "year": N, "month": N, "day": N }. Not a string or ISO date. Default currentYear + 10. |
addRemoveTimeMinDate | string | optional | Runtime 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. |
addRemoveTimeMaxDate | string | optional | Runtime offset applied to maxDate. Same format as addRemoveTimeMinDate. |
allowedDaysOfTheWeek | number[] | optional | Days the user may select. Omit to allow all days. |
startHour | number | optional | Earliest selectable hour in 24h format. Default 8. |
endHour | number | optional | Latest selectable hour in 24h format. Default 16. |
interval | number | optional | Minute interval between time slots. Default 30. |
dateFormat | string | optional | Display format, e.g. "DD MM YYYY". Default "DD MM YYYY". |
delimeter | string | optional | Date part separator, e.g. "/", "-". Default "-". |
eventCode | string | optional | Event code for loading restricted/available dates from the backend. |
eventDatesMaxSize | string | optional | Maximum number of event dates to load. Must be a string, e.g. "5". |
tooltip | string | optional | Help text shown as an icon tooltip next to the label. |
hint | string | optional | Help text rendered below the field, always visible. |
hideField | boolean | optional | Hides the field and excludes its value from submission. Toggle via expressions["props.hideField"]. |
className | string | optional | CSS 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
customdatetimepickerwhen only a date is needed — usecustomdatepickerinstead. - Using
customdatetimepickerwhen only a time is needed — usecustomtimepickerinstead. - Setting
props.required: truedirectly — always usedefaultRequired: truewith the standard expression. - Using
validators: { validation: [...] }instead ofvalidation: { messages: {} }for required messages. - Setting
allowedDaysOfTheWeekwith day names (e.g."Monday") — it must be an array of numbers. - Setting
startHour/endHour/intervalas strings — they must be numbers. - Setting
minDate/maxDateas ISO strings — they must be{ "year": N, "month": N, "day": N }objects.
Checklist
-
keyisUPPER_SNAKE_CASEand unique across the entire form -
props.labelis present, unique, and correctly cased - Field is nested at the correct depth:
sections > formly-group > block > customdatetimepicker -
required: falseis set (nevertrue) -
defaultRequiredis set -
expressions["props.required"]is present with the exact required expression -
validation.messages.requiredis present whendefaultRequired: 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, andintervalare numbers, not strings