Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: explain constraint validation, add error messages #3640

Open
wants to merge 24 commits into
base: latest
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 17 additions & 8 deletions articles/components/_input-field-common-features.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -144,21 +144,24 @@


////
CONSTRAINT FEATURES
VALIDATION FEATURES
////

// tag::constraints-intro[]
[.collapsible-list]
== Constraints
// end::constraints-intro[]

// tag::bad-input[]
[#bad-input]
.Bad Input
[%collapsible]
====
Bad input refers to any input that cannot be parsed into a value of the field type. When an unparsable value is entered, the field resets the value to empty and becomes invalid. This constraint is non-configurable and enabled by default.

Check failure on line 155 in articles/components/_input-field-common-features.adoc

View workflow job for this annotation

GitHub Actions / lint

[vale] reported by reviewdog 🐶 [Vale.Spelling] Did you really mean 'unparsable'? Raw Output: {"message": "[Vale.Spelling] Did you really mean 'unparsable'?", "location": {"path": "articles/components/_input-field-common-features.adoc", "range": {"start": {"line": 155, "column": 93}}}, "severity": "ERROR"}
====
// end::bad-input[]

// tag::required[]
[#required]
.Required
[%collapsible]
====
Required fields are marked with an indicator next to the label, and become invalid if left empty after having been focused. An error message explaining that the field is required needs to be provided manually.
Required fields are marked with an indicator next to the label, and become invalid if their value is first entered and then cleared.

An instruction text at the top of the form explaining the required indicator is recommended. The indicator itself can be customized with the `--lumo-required-field-indicator` style property.
====
Expand Down Expand Up @@ -193,10 +196,16 @@
[%collapsible]
====
A separate single-character, regular expression can be used to restrict the characters that can be entered into the field. Characters that don't match the expression are rejected.

Note, however, that programmatically set values are not subject to this restriction, even if they contain disallowed characters. To validate these values, a pattern constraint can be used in addition.
====
// end::allowed-chars[]


// tag::binder[]
.Data Binding and Custom Validation
[NOTE]
Flow and Hilla offer an advanced API called Binder that allows you to bind data and add custom validation rules for multiple fields, creating forms. You can learn more about Binder from the corresponding <<{articles}/flow/binding-data/components-binder-validation#,Flow>> and <<{articles}/hilla/lit/guides/forms/binder-validation#,Hilla>> articles.
// end::binder[]


////
Expand Down
5 changes: 3 additions & 2 deletions articles/components/combo-box/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -360,9 +360,10 @@ endif::[]
--


// Constraints
[.collapsible-list]
== Validation

include::{articles}/components/_input-field-common-features.adoc[tags=constraints-intro;required;allowed-chars]
include::{articles}/components/_input-field-common-features.adoc[tags=required;allowed-chars]

[.example]
--
Expand Down
25 changes: 19 additions & 6 deletions articles/components/date-picker/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,44 +48,55 @@ endif::[]
The date can be entered directly using the keyboard in the format of the current locale or through the date picker overlay. The overlay opens when the field is clicked or any input is entered when the field is focused.


[.collapsible-list]
== Validation

To validate a date entered or selected, various ways may be used. For instance, you may want to allow only dates in a certain range, or you might not want to allow certain dates. Below are some of your options for date validation.
Date Picker provides a validation mechanism based on constraints. Constraints allow you to define criteria that the date must meet to be considered valid. Validation generally occurs when the user initiates a date change, for example by selecting a date from the overlay or through text input followed by kbd:[Enter]. If the date is invalid, the field is visually highlighted in red, and an error message appears underneath the input.

Below is a list of supported constraints with more detailed information:

=== Min & Max Value
include::{articles}/components/_input-field-common-features.adoc[tags=bad-input,required]

[#min-and-max-value]
.Min & Max Value
[%collapsible]
====
The valid input range of Date Picker can be restricted by defining `min` and `max` values. Dates before the `min` and after the `max` are disabled in the overlay. Helper text can be used to inform the user about the accepted range.
====

The following example demonstrates how to specify these constraints and provide error messages:

[.example]
--

ifdef::lit[]
[source,html]
----
include::{root}/frontend/demo/component/datepicker/date-picker-min-max.ts[render,tags=snippet,indent=0,group=Lit]
include::{root}/frontend/demo/component/datepicker/date-picker-validation.ts[render,tags=snippet,indent=0,group=Lit]
----
endif::[]

ifdef::flow[]
[source,java]
----
include::{root}/src/main/java/com/vaadin/demo/component/datepicker/DatePickerMinMax.java[render,tags=snippet,indent=0,group=Flow]
include::{root}/src/main/java/com/vaadin/demo/component/datepicker/DatePickerValidation.java[render,tags=snippet,indent=0,group=Flow]
----
endif::[]

ifdef::react[]
[source,tsx]
----
include::{root}/frontend/demo/component/datepicker/react/date-picker-min-max.tsx[render,tags=snippet,indent=0,group=React]
include::{root}/frontend/demo/component/datepicker/react/date-picker-validation.tsx[render,tags=snippet,indent=0,group=React]
----
endif::[]
--

It's important to ensure an appropriate error message is configured for each constraint violation to provide users with clear feedback.

ifdef::flow,lit[]
=== Custom Validation

Date Picker supports custom validation, such as limiting the options to Monday through Friday. In the following example, select a date that's on a Sunday or a Saturday to see a custom validation message.
For more advanced cases where constraint validation isn't sufficient, Flow and Hilla offer an API called Binder that allows you to define custom validation rules. This is useful for example when you want to limit the options to Monday through Friday. In the following example, select a date that's on a Sunday or a Saturday to see a custom validation message.

[.example]
--
Expand Down Expand Up @@ -113,6 +124,8 @@ endif::[]
--
endif::[]

Binder can also be used to organize data binding and validation for multiple fields, creating forms. You can learn more about Binder from the corresponding <<{articles}/flow/binding-data/components-binder-validation#,Flow>> and <<{articles}/hilla/lit/guides/forms/binder-validation#,Hilla>> articles.

== Week Numbers

pass:[<!-- vale Vaadin.Abbr = NO --> ]
Expand Down
24 changes: 17 additions & 7 deletions articles/components/email-field/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -75,43 +75,53 @@ endif::[]
--


// Constraints
[.collapsible-list]
== Validation

include::{articles}/components/_input-field-common-features.adoc[tags=constraints-intro;required]
Email Field provides a validation mechanism based on constraints. Constraints allow you to define criteria that the value must meet to be considered valid. Validation generally occurs when the user initiates a value change, for example by entering input and pressing kbd:[Enter]. If the value is invalid, the field is visually highlighted in red, and an error message appears underneath the input.

Below is a list of supported constraints with more detailed information:

include::{articles}/components/_input-field-common-features.adoc[tags=required]

[#pattern]
.Pattern
[%collapsible]
====
The pattern attribute is an additional validation criterion that you can set if, for example, a specific domain is required. The pattern is specified using a regular expression.
The pattern is a regular expression that specifies an email format. Any value that doesn't match the email format invalidates the field. By default, the https://tools.ietf.org/html/rfc5322#[RFC 5322] standard pattern is used. However, you can modify this pattern to add additional restrictions, for example, to require a specific domain.

The example below uses the pattern `.+@example\.com` and only accepts addresses in the `example.com` domain.
The example below uses a modified version of the RFC 5322 pattern and only accepts addresses in the `example.com` domain.
====

The following example demonstrates how to specify these constraints and provide error messages:

[.example]
--
ifdef::lit[]
[source,typescript]
----
include::{root}/frontend/demo/component/emailfield/email-field-constraints.ts[render,tags=snippet,indent=0,group=Lit]
include::{root}/frontend/demo/component/emailfield/email-field-validation.ts[render,tags=snippet,indent=0,group=Lit]
----
endif::[]

ifdef::flow[]
[source,java]
----
include::{root}/src/main/java/com/vaadin/demo/component/emailfield/EmailFieldConstraints.java[render,tags=snippet,indent=0,group=Flow]
include::{root}/src/main/java/com/vaadin/demo/component/emailfield/EmailFieldValidation.java[render,tags=snippet,indent=0,group=Flow]
----
endif::[]

ifdef::react[]
[source,tsx]
----
include::{root}/frontend/demo/component/emailfield/react/email-field-constraints.tsx[render,tags=snippet,indent=0,group=React]
include::{root}/frontend/demo/component/emailfield/react/email-field-validation.tsx[render,tags=snippet,indent=0,group=React]
----
endif::[]
--

It's important to ensure an appropriate error message is configured for each constraint violation to provide users with clear feedback.

include::{articles}/components/_input-field-common-features.adoc[tags=binder]

// Readonly and disabled

Expand Down
10 changes: 8 additions & 2 deletions articles/components/password-field/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,15 @@ endif::[]
--


// Constraints
[.collapsible-list]
== Validation

include::{articles}/components/_input-field-common-features.adoc[tags=constraints-intro;required;min-and-max-length;allowed-chars]
Password Field provides a validation mechanism based on constraints. Constraints allow you to define criteria that the value must meet to be considered valid. Validation generally occurs when the user initiates a value change, for example by entering input and pressing kbd:[Enter]. If the value is invalid, the field is visually highlighted in red, and an error message appears underneath the input.

Below is a list of supported constraints with more detailed information:


include::{articles}/components/_input-field-common-features.adoc[tags=required;min-and-max-length;allowed-chars]

[.example]
--
Expand Down
10 changes: 8 additions & 2 deletions articles/components/text-area/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,15 @@ endif::[]
--


// Constraints
[.collapsible-list]
== Validation

include::{articles}/components/_input-field-common-features.adoc[tags=constraints-intro;required;pattern;min-and-max-length;allowed-chars]
Text Area provides a validation mechanism based on constraints. Constraints allow you to define criteria that the value must meet to be considered valid. Validation generally occurs when the user initiates a value change, for example by entering input and pressing kbd:[Enter]. If the value is invalid, the field is visually highlighted in red, and an error message appears underneath the input.

Below is a list of supported constraints with more detailed information:


include::{articles}/components/_input-field-common-features.adoc[tags=required;pattern;min-and-max-length;allowed-chars]

[.example]
--
Expand Down
22 changes: 17 additions & 5 deletions articles/components/text-field/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -71,34 +71,46 @@ endif::[]
--


// Constraints
[.collapsible-list]
== Validation

include::{articles}/components/_input-field-common-features.adoc[tags=constraints-intro;required;pattern;min-and-max-length;allowed-chars]
Text Field provides a validation mechanism based on constraints. Constraints allow you to define criteria that the value must meet to be considered valid. Validation generally occurs when the user initiates a value change, for example by entering input and pressing kbd:[Enter]. If the value is invalid, the field is visually highlighted in red, and an error message appears underneath the input.

Below is a list of supported constraints with more detailed information:

[.example]

include::{articles}/components/_input-field-common-features.adoc[tags=required;pattern;min-and-max-length;allowed-chars]

The following example demonstrates how to specify these constraints and provide error messages:

[.example]
--
ifdef::lit[]
[source,typescript]
----
include::{root}/frontend/demo/component/textfield/text-field-constraints.ts[render,tags=snippet,indent=0,group=Lit]
include::{root}/frontend/demo/component/textfield/text-field-validation.ts[render,tags=snippet,indent=0,group=Lit]
----
endif::[]

ifdef::flow[]
[source,java]
----
include::{root}/src/main/java/com/vaadin/demo/component/textfield/TextFieldConstraints.java[render,tags=snippet,indent=0,group=Flow]
include::{root}/src/main/java/com/vaadin/demo/component/textfield/TextFieldValidation.java[render,tags=snippet,indent=0,group=Flow]
----
endif::[]

ifdef::react[]
[source,tsx]
----
include::{root}/frontend/demo/component/textfield/react/text-field-constraints.tsx[render,tags=snippet,indent=0,group=React]
include::{root}/frontend/demo/component/textfield/react/text-field-validation.tsx[render,tags=snippet,indent=0,group=React]
----
endif::[]
--

It's important to ensure an appropriate error message is configured for each constraint violation to provide users with clear feedback.

include::{articles}/components/_input-field-common-features.adoc[tags=binder]

// Readonly and disabled

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import 'Frontend/demo/init'; // hidden-source-line
import { html, LitElement } from 'lit';
import { customElement, state } from 'lit/decorators.js';
import '@vaadin/date-picker';
import type { DatePickerChangeEvent } from '@vaadin/date-picker';
import type { DatePicker, DatePickerValidatedEvent } from '@vaadin/date-picker';
import { applyTheme } from 'Frontend/generated/theme';
import { addDays, formatISO, isAfter, isBefore } from 'date-fns';
import dateFnsParse from 'date-fns/parse';

@customElement('date-picker-min-max')
@customElement('date-picker-validation')
export class Example extends LitElement {
protected override createRenderRoot() {
const root = super.createRenderRoot();
Expand All @@ -31,13 +31,20 @@ export class Example extends LitElement {
<!-- tag::snippet[] -->
<vaadin-date-picker
label="Appointment date"
required
helper-text="Must be within 60 days from today"
.min="${formatISO(this.minDate, { representation: 'date' })}"
.max="${formatISO(this.maxDate, { representation: 'date' })}"
.errorMessage="${this.errorMessage}"
@change="${({ target }: DatePickerChangeEvent) => {
const date = dateFnsParse(target.value ?? '', 'yyyy-MM-dd', new Date());
if (isBefore(date, this.minDate)) {
@validated="${(event: DatePickerValidatedEvent) => {
const field = event.target as DatePicker;
const date = dateFnsParse(field.value ?? '', 'yyyy-MM-dd', new Date());
const inputElement = field.inputElement as HTMLInputElement;
if (!field.value && inputElement.value) {
this.errorMessage = 'Invalid date format';
} else if (!field.value) {
this.errorMessage = 'Field is required';
} else if (isBefore(date, this.minDate)) {
this.errorMessage = 'Too early, choose another date';
} else if (isAfter(date, this.maxDate)) {
this.errorMessage = 'Too late, choose another date';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { reactExample } from 'Frontend/demo/react-example'; // hidden-source-lin
import React from 'react'; // hidden-source-line
import { useComputed, useSignal } from '@vaadin/hilla-react-signals';
import { useSignals } from '@preact/signals-react/runtime'; // hidden-source-line
import { DatePicker } from '@vaadin/react-components/DatePicker.js';
import { DatePicker, type DatePickerElement } from '@vaadin/react-components/DatePicker.js';
import { formatISO, addDays, isBefore, isAfter, parse } from 'date-fns';

function Example() {
Expand All @@ -19,9 +19,15 @@ function Example() {
min={formatISO(minDate.value, { representation: 'date' })}
max={formatISO(maxDate.value, { representation: 'date' })}
errorMessage={errorMessage.value}
onChange={({ target }) => {
const date = parse(target.value ?? '', 'yyyy-MM-dd', new Date());
if (isBefore(date, minDate.value)) {
onValidated={(event) => {
const field = event.target as DatePickerElement;
const date = parse(field.value ?? '', 'yyyy-MM-dd', new Date());
const inputElement = field.inputElement as HTMLInputElement;
if (!field.value && inputElement.value) {
errorMessage.value = 'Invalid date format';
} else if (!field.value) {
errorMessage.value = 'Field is required';
} else if (isBefore(date, minDate.value)) {
errorMessage.value = 'Too early, choose another date';
} else if (isAfter(date, maxDate.value)) {
errorMessage.value = 'Too late, choose another date';
Expand Down
30 changes: 0 additions & 30 deletions frontend/demo/component/emailfield/email-field-constraints.ts

This file was deleted.

Loading
Loading