Skip to main content
umbraco-validation-context Implement form validation using UmbValidationContext in Umbraco backoffice
Zur Installation springen Skills Marktplatz Entdecken und erkunden Sie KI-Skills, die von der Community erstellt wurden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Prompt kopierenPrompt-Details anzeigen Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
npx skills add https://github.com/umbraco/Umbraco-CMS-Backoffice-Skills --skill umbraco-validation-contextDer Befehl bleibt in einer Zeile. Scrollen Sie horizontal, um ihn vor dem Kopieren vollständig zu prüfen.
Sie bevorzugen eine lokale Kopie? Laden Sie die Dateien herunter, die SkillsMP derzeit vorliegen.
ZIP herunterladen Herunterladen... Mehr aus diesem Repository Verwandte Berufe
SOC
Basierend auf der SOC-Berufsklassifikation
name umbraco-validation-context description Implement form validation using UmbValidationContext in Umbraco backoffice version 1.0.0 location managed allowed-tools Read, Write, Edit, WebFetch
Umbraco Validation Context
What is it?
UmbValidationContext provides a centralized validation system for forms in the Umbraco backoffice. It manages validation messages using JSON Path notation, supports both client-side and server-side validation, and enables reactive error counting for tabs and sections. This is essential for multi-step forms, workspace editors, and any UI that requires comprehensive validation feedback.
Documentation
Always fetch the latest docs before implementing:
Reference Examples
The Umbraco source includes working examples:
Validation Context Dashboard : /Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/validation-context/
This example demonstrates multi-tab form validation with error counting.
Custom Validation Workspace Context : /Umbraco-CMS/src/Umbraco.Web.UI.Client/examples/custom-validation-workspace-context/
This example shows workspace-level validation patterns.
Related Foundation Skills
Workflow
Fetch docs - Use WebFetch on the URLs above
Ask questions - What fields? What validation rules? Multi-tab form?
Generate files - Create form element with validation context
Explain - Show what was created and how validation works
Basic Setup
import { html, customElement, state } from '@umbraco-cms/backoffice/external/lit' ;
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element' ;
import {
UMB_VALIDATION_CONTEXT ,
umbBindToValidation,
UmbValidationContext ,
} from '@umbraco-cms/backoffice/validation' ;
import type { UmbValidationMessage } from '@umbraco-cms/backoffice/validation' ;
@customElement ('my-validated-form' )
export class MyValidatedFormElement extends UmbLitElement {
readonly validation = new UmbValidationContext (this );
@state ()
private _name = '' ;
@state ()
private _email = '' ;
@state ()
private _messages ?: UmbValidationMessage [];
constructor ( ) {
super ();
this .consumeContext (UMB_VALIDATION_CONTEXT , ( ) => {
. (
validationContext?. . ,
{
. = messages;
},
);
});
}
( ) {
html` ;
}
# ( ) {
isValid = . . ();
(isValid) {
. ( );
}
}
}
Multi-Tab Form with Error Counting
import { html, customElement, state, when } from '@umbraco-cms/backoffice/external/lit' ;
import { UmbLitElement } from '@umbraco-cms/backoffice/lit-element' ;
import { UmbValidationContext , umbBindToValidation } from '@umbraco-cms/backoffice/validation' ;
@customElement ('my-tabbed-form' )
export class MyTabbedFormElement extends UmbLitElement {
readonly validation = new UmbValidationContext (this );
@state () private _tab = '1' ;
@state () private _totalErrors = 0 ;
@state () private _tab1Errors = 0 ;
@state () private _tab2Errors = 0 ;
@state () private _name = '' ;
@state () private _email = '' ;
@state () private _city = '' ;
@state () private _country = '' ;
constructor ( ) {
super ();
. (
. . . ( ),
{
. = [... (messages. ( x. ))]. ;
}
);
. (
. . . ( ),
{
. = [... (messages. ( x. ))]. ;
}
);
. (
. . . ( ),
{
. = [... (messages. ( x. ))]. ;
}
);
}
( ) {
html` ;
}
# ( ) {
html` ;
}
# ( ) {
html` ;
}
# ( ) {
. = (e. ). ( ) ?? ;
}
# ( ) {
isValid = . . ();
(!isValid) {
. ( );
}
}
}
Server-Side Validation Errors
Add server validation errors after an API call:
async #handleSave ( ) {
const isValid = await this .validation .validate ();
if (!isValid) return ;
try {
const response = await this .#saveToServer ();
if (!response.ok ) {
const errors = await response.json ();
for (const error of errors.validationErrors ) {
this .validation .messages .addMessage (
'server' ,
error.path ,
error.message ,
crypto.randomUUID ()
);
}
}
} catch (error) {
console .error ('Save failed:' , error);
}
}
Key APIs
UmbValidationContext
const validation = new UmbValidationContext (this );
const isValid = await validation.validate ();
validation.messages ;
Validation Messages
validation.messages .addMessage (source, path, message, key);
validation.messages .removeMessagesBySource ('server' );
this .observe (
validation.messages .messagesOfPathAndDescendant ('$.form.tab1' ),
(messages ) => { }
);
this .observe (
validation.messages .messages ,
(messages ) => { }
);
umbBindToValidation Directive
${umbBindToValidation (this , '$.form.fieldName' , fieldValue)}
JSON Path Notation
Validation uses JSON Path to identify fields:
Path Description $.formRoot form object $.form.nameName field $.form.tab1.emailEmail field in tab1 $.form.items[0].valueFirst item's value $.form.items[*].nameAll item names
Validation Message Interface
interface UmbValidationMessage {
source : string ;
path : string ;
message : string ;
key : string ;
}
Best Practices
Use JSON Path hierarchy - Organize paths by tab/section for easy error counting
Wrap inputs - Use <uui-form-validation-message> around inputs
Clear server errors - Remove old server errors before new validation
Unique keys - Use crypto.randomUUID() for server error keys
Observe specific paths - Use messagesOfPathAndDescendant for scoped error counts
Show counts on tabs - Display error badges to guide users to problems
That's it! Always fetch fresh docs, keep examples minimal, generate complete working code.
validationContext
this
observe
messages
messages
(messages ) =>
this
_messages
'observeValidationMessages'
override
render
return
<uui-form >
<form >
<div >
<label > Name</label >
<uui-form-validation-message >
<uui-input
type ="text"
.value =
${this ._name}
@input =
${(e: InputEvent) => (this ._name = (e.target as HTMLInputElement).value)}
${umbBindToValidation(this , '$.form.name' , this ._name)}
required
> </uui-input >
</uui-form-validation-message >
</div >
<div >
<label > Email</label >
<uui-form-validation-message >
<uui-input
type ="email"
.value =
${this ._email}
@input =
${(e: InputEvent) => (this ._email = (e.target as HTMLInputElement).value)}
${umbBindToValidation(this , '$.form.email' , this ._email)}
required
> </uui-input >
</uui-form-validation-message >
</div >
<uui-button look ="primary" @click =
${this .#handleSave}
> Save</uui-button >
</form >
</uui-form >
<pre >
${JSON .stringify(this ._messages ?? [], null , 2 )}
</pre >
`
async
handleSave
const
await
this
validation
validate
if
console
log
'Form is valid!'
this
observe
this
validation
messages
messagesOfPathAndDescendant
'$.form'
(messages ) =>
this
_totalErrors
new
Set
map
(x ) =>
path
length
this
observe
this
validation
messages
messagesOfPathAndDescendant
'$.form.tab1'
(messages ) =>
this
_tab1Errors
new
Set
map
(x ) =>
path
length
this
observe
this
validation
messages
messagesOfPathAndDescendant
'$.form.tab2'
(messages ) =>
this
_tab2Errors
new
Set
map
(x ) =>
path
length
override
render
return
<uui-box >
<p > Total errors:
${this ._totalErrors}
</p >
<uui-tab-group @click =
${this .#onTabChange}
>
<uui-tab ?active =
${this ._tab === '1' }
data-tab ="1" >
Tab 1
${when(
this ._tab1Errors,
() => html`<uui-badge color ="danger" > ${this ._tab1Errors} </uui-badge > `
)}
</uui-tab >
<uui-tab ?active =
${this ._tab === '2' }
data-tab ="2" >
Tab 2
${when(
this ._tab2Errors,
() => html`<uui-badge color ="danger" > ${this ._tab2Errors} </uui-badge > `
)}
</uui-tab >
</uui-tab-group >
${when(this ._tab === '1' , () => this .#renderTab1())}
${when(this ._tab === '2' , () => this .#renderTab2())}
<uui-button look ="primary" @click =
${this .#handleSave}
> Save</uui-button >
</uui-box >
`
renderTab1
return
<uui-form >
<form >
<label > Name</label >
<uui-form-validation-message >
<uui-input
.value =
${this ._name}
@input =
${(e: InputEvent) => (this ._name = (e.target as HTMLInputElement).value)}
${umbBindToValidation(this , '$.form.tab1.name' , this ._name)}
required
> </uui-input >
</uui-form-validation-message >
<label > Email</label >
<uui-form-validation-message >
<uui-input
type ="email"
.value =
${this ._email}
@input =
${(e: InputEvent) => (this ._email = (e.target as HTMLInputElement).value)}
${umbBindToValidation(this , '$.form.tab1.email' , this ._email)}
required
> </uui-input >
</uui-form-validation-message >
</form >
</uui-form >
`
renderTab2
return
<uui-form >
<form >
<label > City</label >
<uui-form-validation-message >
<uui-input
.value =
${this ._city}
@input =
${(e: InputEvent) => (this ._city = (e.target as HTMLInputElement).value)}
${umbBindToValidation(this , '$.form.tab2.city' , this ._city)}
required
> </uui-input >
</uui-form-validation-message >
<label > Country</label >
<uui-form-validation-message >
<uui-input
.value =
${this ._country}
@input =
${(e: InputEvent) => (this ._country = (e.target as HTMLInputElement).value)}
required
> </uui-input >
</uui-form-validation-message >
</form >
</uui-form >
`
onTabChange
e : Event
this
_tab
target
as
HTMLElement
getAttribute
'data-tab'
'1'
async
handleSave
const
await
this
validation
validate
if
console
log
'Form has validation errors'