Hi there
Feeling a bit overwhelmed and struggling to find the approach on how to use and set custom validation messages on a property editor.
I am building a date range property editor and need to set a couple of custom validation messages:
End Date is required
Start Date is required
End Date can not be before the start date
Screenshot
Current Code
import { UmbInputDateElement } from '@umbraco-cms/backoffice/components';
import { UmbChangeEvent } from '@umbraco-cms/backoffice/event';
import { css, customElement, html, nothing, property, state } from '@umbraco-cms/backoffice/external/lit';
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element';
import type { UmbPropertyEditorConfigCollection, UmbPropertyEditorUiElement } from '@umbraco-cms/backoffice/property-editor';
import { UmbTextStyles } from '@umbraco-cms/backoffice/style';
interface DateRangeValue {
StartDate: string | null;
EndDate: string | null;
}
@customElement('date-range-picker')
export default class DateRangePickerElement extends UmbLitElement implements UmbPropertyEditorUiElement {
@property({ type: Boolean, reflect: true })
readonly = false;
@property({ type: Boolean, reflect: true })
mandatory?: boolean;
@property()
mandatoryMessage?: string;
/*
{
"StartDate": "2021-04-15 00:00:00", // Can I parse this to be a Date object in JS (Technically missing the T part)
"EndDate": null
}
*/
@property({ type: Object })
value: Partial<DateRangeValue> = {};
/*
[
{
"alias": "endDateIsRequired",
"value": true
},
{
"alias": "enableTimePicker",
"value": false
}
]
*/
set config(value: UmbPropertyEditorConfigCollection | undefined) {
this._endDateIsRequired = value?.getValueByAlias('endDateIsRequired') ?? false;
this._enableTimePicker = value?.getValueByAlias('enableTimePicker') ?? false;
}
// Add validation method
#validateDateRange(): void {
const startDate = this.value?.StartDate ? new Date(this.value.StartDate) : null;
const endDate = this.value?.EndDate ? new Date(this.value.EndDate) : null;
// Check if end date comes before start date
this._isDateRangeInvalid = !!(startDate && endDate && endDate < startDate);
// TODO: How do I use some native validation ?!
}
@state()
private _isDateRangeInvalid: boolean = false;
@state()
private _endDateIsRequired: boolean = false;
@state()
private _enableTimePicker: boolean = false;
#onInputStart(e: InputEvent) {
// 2025-06-03
// 2025-06-08T19:00
const startDateValue = (e.target as UmbInputDateElement).value.toString();
console.log('Start Date Value:', startDateValue);
const parsedDate = startDateValue ? new Date(startDateValue) : null;
console.log('Parsed Start Date:', parsedDate);
// Set date as this format '2025-06-08T19:00'
const formattedDate = this.formatDateForInput(parsedDate);
this.value = {
...this.value,
StartDate: formattedDate
};
this.dispatchEvent(new UmbChangeEvent());
this.#validateDateRange();
}
#onInputEnd(e: InputEvent) {
// 2025-06-03
// 2025-06-08T19:00
const endDateValue = (e.target as UmbInputDateElement).value.toString();
console.log('END Date Value:', endDateValue);
const parsedDate = endDateValue ? new Date(endDateValue) : null;
console.log('Parsed END Date:', parsedDate);
// Set date as this format '2025-06-08T19:00'
const formattedDate = this.formatDateForInput(parsedDate);
this.value = {
...this.value,
EndDate: formattedDate
};
this.dispatchEvent(new UmbChangeEvent());
this.#validateDateRange();
}
private formatDateForInput(date: Date | null): string {
if (!date) return '';
// Get local date/time components
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
if(!this._enableTimePicker) {
return `${year}-${month}-${day}`; // Format as 'YYYY-MM-DD' for date input
}
// Format as 'YYYY-MM-DDTHH:MM' for datetime-local input
return `${year}-${month}-${day}T${hours}:${minutes}`;
}
constructor() {
super();
// If we need to observe or consume contexts
}
override render() {
return html`
<div class="date-inputs">
<div class="date-field">
<uui-label>Start Date</uui-label>
<umb-input-date
@input=${this.#onInputStart}
.value=${this.value?.StartDate ?? ''}
.type=${this._enableTimePicker ? 'datetime-local' : 'date'}></umb-input-date>
</div>
<div class="date-field">
<uui-label>End Date ${this._endDateIsRequired ? html `<span class="required">*</span>`: nothing}</uui-label>
<umb-input-date
@input=${this.#onInputEnd}
.value=${this.value?.EndDate ?? ''}
.min=${this.value?.StartDate ?? ''}
.type=${this._enableTimePicker ? 'datetime-local' : 'date'}
?required=${this._endDateIsRequired}></umb-input-date>
</div>
</div>
${this._isDateRangeInvalid ?
html`
<div class="validation-message">
<uui-icon name="icon-alert" style="color: var(--uui-color-danger);"></uui-icon>
End date cannot be before start date
</div>`
: nothing
}
<umb-code-block language="value">
${JSON.stringify(this.value, null, 2)}
</umb-code-block>
<pre>
End date is required: ${this._endDateIsRequired}
Enable Time Picker: ${this._enableTimePicker}
Value.StartDate: ${this.value?.StartDate}
Value.EndDate: ${this.value?.EndDate}
Readonly: ${this.readonly}
Mandatory: ${this.mandatory}
Mandatory Message: ${this.mandatoryMessage}
</pre>
`;
}
static override readonly styles = [
UmbTextStyles,
css`
uui-input {
width: 100%;
}
.date-inputs {
display: flex;
gap: 1rem;
align-items: flex-start
}
uui-label {
display:block;
}
.required {
color: var(--uui-color-danger);
font-weight: 900;
}
`,
];
}
declare global {
interface HTMLElementTagNameMap {
'date-range-picker': DateRangePickerElement;
}
}
Existing Docs
The existing documentation for validation is quite detailed and I am not sure I understand how to use it and nor does it talk about setting any custom validation messages. What am I missing?
In addition to this the tutorial for creating a property editor, seems to encourage server side validation approach and does not cover the scenario of using client side validation
Perhaps one for the docs team to add/improve on?
Any pointers or advice
So do you have any pointers or advice on what I need to be doing to set custom validation messages for this property editor?