For the most validations, the HTML5 Form data validations is sufficient. When more fine grained control is needed Custom validations will do the job.
Add data-validate="true" to validate forms.
By default HTML5 Form data validation is used:
novalidaterequired*minlength / minlength if textual input.pattern if textual input.requiredminlengthPlease refer to the specific input fields for all options.
* Not in combination with attribute multiple
<!-- Form -->
<form action="#form-38087a" autocomplete="off" class="vi-form vi-typesystem" data-validate="true" novalidate>
<div class="form-group">
<label for="control-a5c899">Email Address
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-d6b764" aria-required="true" class="form-control" id="control-a5c899" name="name-10e71b" placeholder="Email Address" required type="email">
<div id="help-d6b764" class="vi-form__feedback vi-form__feedback--hint">Basic validation (basicly only ab@bc is needed, since [type='email'], no TLD is required.)</div>
</div>
<div class="form-group">
<label for="control-1506dc">Email Address
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-87cdc9" aria-required="true" class="form-control" id="control-1506dc" name="name-2d1288" pattern="[^@\s]+@[^@\s]+\.[^@\s]+" placeholder="Email Address" required type="email">
<div id="help-87cdc9" class="vi-form__feedback vi-form__feedback--hint">Pattern validation using [^@\s]+@[^@\s]+\.[^@\s]+ to require a TLD (see pattern attribute)</div>
</div>
<div class="form-group">
<label for="control-bd15e4">Greet me
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-2c98e1" aria-required="true" class="form-control" id="control-bd15e4" name="name-697a06" pattern="hello world" placeholder="Greet me" required type="text">
<div id="help-2c98e1" class="vi-form__feedback vi-form__feedback--hint">Pattern validation only allows 'hello world' (see pattern attibute)</div>
</div>
<div class="form-group">
<label for="control-8e84d6">Say something between 5 and 10 characters.
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<textarea aria-describedby="help-d6d67a" aria-required="true" class="form-control" id="control-8e84d6" maxlength="10" minlength="5" name="name-90d2bc" placeholder="Say something between 5 and 10 characters." required></textarea>
<div id="help-d6d67a" class="vi-form__feedback vi-form__feedback--hint">Minlength and maxlength applied</div>
</div>
<div class="form-group">
<div class="custom-checkbox custom-control">
<input aria-required="true" class="custom-control-input" id="control-b68db6" name="name-cb822c" required type="checkbox">
<label class="custom-control-label" for="control-b68db6">
Yes! Contact me all on available channels.
</label>
</div>
</div>
<!-- Button type: solid -->
<button type="submit" class="vi-btn-solid vi-btn">Hit me</button>
</form>
Without any further settings the browsers default messages are displayed (depending the language of the browser/OS).
To have better control over the message the folloing data attributes are supported:
data-msg The default validation messagedata-msg-success Provide positive feedback on success.More fine grained options will be added in the future.
<!-- Form -->
<form action="#form-6a2c55" autocomplete="off" class="vi-form vi-typesystem" data-validate="true" novalidate>
<div class="form-group">
<label for="control-c66b73">Greet me
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-4c0410" aria-required="true" class="form-control" data-msg-success="And hello back to you!" data-msg="This is not a hello world" id="control-c66b73" name="name-828ee3" pattern="hello world" placeholder="Greet me" required type="text">
<div id="help-4c0410" class="vi-form__feedback vi-form__feedback--hint">Start typing 'hello world' to see examples of custom feedback messages.</div>
</div>
<!-- Button type: solid -->
<button type="submit" class="vi-btn-solid vi-btn">Hit me</button>
</form>
The legacy method of adding messages still work. The elements are converted to data attributes by javascript.
<!-- by placing this afther form field. -->
<div class="valid-feedback">Example of positive feedback</div>
<div class="invalid-feedback">Example of negative feedback</div>
Add data-validate="true" to validate forms.
For custom validation, attach an eventHandler to form or field:
<script>
$(...).on('validate', function(e, field, valid, invalid, eventType) {
//... your logic ...
}
</script>
The eventHandler takes the following arguments:
e jQuery eventObjectfield jQuery Object of current form fieldisValid callback function with arguments 'state' and 'message'eventType String [submit | input | blur] depending internal initiator of callback.The logic of the eventHandler should in a call to valid() or invalid() (or none of both)
<!-- Form -->
<form action="#to-the-server" autocomplete="off" class="vi-form vi-typesystem" data-validate="true" id="form-6ac038" novalidate>
<div class="form-group">
<label for="form-6ac038--field-1">Share your secret
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-a6d822" aria-required="true" class="form-control" id="form-6ac038--field-1" name="name-8be925" placeholder="Say !Welcome1234" required type="text">
<div id="help-a6d822" class="vi-form__feedback vi-form__feedback--hint">Custom validation (event attached to form)</div>
</div>
<div class="form-group">
<label for="form-6ac038--field-2">Rock scissors paper
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-41e377" aria-required="true" class="form-control" id="form-6ac038--field-2" name="name-a62b91" placeholder="rock, scissors or paper" required type="text">
<div id="help-41e377" class="vi-form__feedback vi-form__feedback--hint">Custom validation (event attached to field)</div>
</div>
<div class="form-group">
<label for="form-6ac038--field-3">Unique username
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-describedby="help-9d1aa4" aria-required="true" class="form-control" data-msg="hmmmm" id="form-6ac038--field-3" name="name-a0ad53" placeholder="Unique username (try starlord, ironman or spiderman)" required type="text">
<div id="help-9d1aa4" class="vi-form__feedback vi-form__feedback--hint">Custom validation (delayed)</div>
</div>
<!-- Button type: solid -->
<button type="submit" class="vi-btn-solid vi-btn">Hit me</button>
</form>
The javascript used by this example.
<!-- the form script -->
<script src="/assets/javascripts/form_teva_scs.bundle-cfe189bc9cb6629a8ad3.js"></script>
<!-- your custom validation -->
<script>
$(function() {
// Example 1 where we attach an eventHandler to the form
$('#form-6ac038').on('validate', function(e, field, isValid) {
// When attached to form, we have to check what field is currently
// being validated.
if (field.is('#form-6ac038--field-1')) {
// Test the field value agains some js logic
if (/\!Welcome1234/.test(field.val())) {
isValid(true, 'Well done! Welcome!')
} else {
isValid(false, 'This is not !Welcome1234')
}
}
})
// Example 2 where we attach an eventHandler to the field
$('#form-6ac038--field-2').on('validate', function(e, field, isValid) {
// Test the field value agains some js logic
switch (field.val()) {
case 'rock':
isValid(true, 'You choose rock!')
break;
case 'scissors':
isValid(true, 'You choose scissors!')
break;
case 'paper':
isValid(true, 'You choose paper!')
break;
default:
isValid(false, 'Must be rock, scissors or paper.')
}
})
// Example 3 where we attach an eventHandler to the field
var timeoutId;
$('#form-6ac038--field-3').on('validate', function(e, field, isValid, eventType) {
// Bail if ...
if (field.val().length < 3) {
isValid(false, 'Username too short')
return;
}
// Bail if not 'input' event
// eventType can be 'submit' | 'input' | 'blur'
// (We only want to simulate remote call on typing)
if (eventType != 'input') return
// Simulated remote call here.
// Please Note: a form can be submitted while fetching.
// Serverside validation is always recommended
clearTimeout(timeoutId)
timeoutId = setTimeout(function() {
if (/^(starlord|ironman|spiderman)$/.test(field.val())) {
isValid(true, 'You can use this name!')
} else {
isValid(false, 'Already in use')
}
}, 1000)
})
})
</script>
Here follow some examples of usage for custom validation
HTML5 does not provide an out-of-the-box way to validate a group of checkboxes.
The group is given an id, used to scope the input fields for validation.
<!-- Form -->
<form action="#to-the-server" autocomplete="off" class="vi-form vi-typesystem" data-validate="true" id="sg-5c6990" novalidate>
<div class="form-group" id="sg-06d582">
<div class="custom-checkbox custom-control">
<input class="custom-control-input" id="control-08d299" name="name-dee787" type="checkbox">
<label class="custom-control-label" for="control-08d299">
Leggings sriracha pabst.
</label>
</div>
<div class="custom-checkbox custom-control">
<input class="custom-control-input" id="control-7596dd" name="name-69527a" type="checkbox">
<label class="custom-control-label" for="control-7596dd">
8-bit thundercats franzen.
</label>
</div>
<div class="custom-checkbox custom-control">
<input class="custom-control-input" id="control-a12898" name="name-75d228" type="checkbox">
<label class="custom-control-label" for="control-a12898">
Paleo tumblr bespoke.
</label>
</div>
<div class="custom-checkbox custom-control" id="sg-613718">
<input class="custom-control-input" id="control-675408" name="name-dba4b3" type="checkbox">
<label class="custom-control-label" for="control-675408">
Flannel roof lumbersexual.
</label>
</div>
</div>
<!-- Button type: solid -->
<button type="submit" class="vi-btn-solid vi-btn">Thundercats meggings</button>
</form>
<script>
$(function() {
$('#sg-613718').on('validate', function(e, field, isValid, eventType) {
if (eventType != 'submit') return;
// if all checkboxed in group checked.
if ($('#sg-06d582 :checkbox:checked').length) {
isValid(true)
} else {
isValid(false, 'Please select at least one box');
}
});
})
</script>
The javascript used by this example.
<script>
$(function() {
$('#id-of-last-checkbox').on('validate', function(e, field, isValid, eventType) {
if (eventType != 'submit') return;
// if all checkboxed in group checked.
if ($('#id-of-group :checkbox:checked').length) {
isValid(true)
} else {
isValid(false, 'Please select at least one box');
}
});
})
</script>
To only allow values from a datalist.
<!-- Form -->
<form action="#form-c0120a" autocomplete="off" class="vi-form vi-typesystem" data-validate="true" novalidate>
<div class="form-group">
<label for="sg-d93619">Country
<span aria-hidden="true" class="vi-form__required">(required)</span></label>
<input aria-required="true" class="form-control" id="sg-d93619" list="countries" name="name-d88b28" placeholder="Country" required type="text">
<datalist id="countries">
<option>Russia</option>
<option>Germany</option>
<option>United Kingdom</option>
<option>France</option>
<option>Italy</option>
<option>Spain</option>
<option>Ukraine</option>
<option>Poland</option>
<option>Romania</option>
<option>Netherlands</option>
<option>Belgium</option>
<option>Czech Republic</option>
<option>Greece</option>
<option>Portugal</option>
<option>Sweden</option>
<option>Hungary</option>
<option>Belarus</option>
<option>Austria</option>
<option>Serbia</option>
<option>Switzerland</option>
<option>Bulgaria</option>
<option>Denmark</option>
<option>Finland</option>
<option>Slovakia</option>
<option>Norway</option>
<option>Ireland</option>
<option>Croatia</option>
<option>Moldova</option>
<option>Bosnia and Herzegovina</option>
<option>Albania</option>
<option>Lithuania</option>
<option>North Macedonia</option>
<option>Slovenia</option>
<option>Latvia</option>
<option>Estonia</option>
<option>Montenegro</option>
<option>Luxembourg</option>
<option>Malta</option>
<option>Iceland</option>
<option>Andorra</option>
<option>Monaco</option>
<option>Liechtenstein</option>
<option>San Marino</option>
<option>Holy See</option>
</datalist>
</div>
<!-- Button type: solid -->
<button type="submit" class="vi-btn-solid vi-btn">Twee +1</button>
</form>
<script>
$(function() {
$('#sg-d93619').on('validate', function(e, field, isValid, eventType) {
// Build array of allowed values from related datalist
var options = $('#' + field.attr('list')).find('option').map(function(index, option) {
return $(option).text();
}).toArray()
// If the array includes the fields value
if (options.includes(field.val())) {
isValid(true)
} else {
isValid(false, 'Value must equal suggestion');
}
});
})
</script>
The javascript used by this example.
<script>
$(function() {
$('#id-of-the-field-with-the-datalist').on('validate', function(e, field, isValid, eventType) {
// Build array of allowed values from related datalist
var options = $('#' + field.attr('list')).find('option').map(function(index, option) {
return $(option).text();
}).toArray()
// If the array includes the fields value
if (options.includes(field.val())) {
isValid(true)
} else {
isValid(false, 'Value must equal suggestion');
}
});
})
</script>
The following stylesheets are required to display this component.
The following javascript is required to display this component.
Usage documentation can be found here.
Changelog
Fix
- 19 Feb 2025 - fix(form): resolve mutation observer recursion issue in Safari
- 13 Feb 2025 - feat(form): fix form reset validation messages
- 11 Sep 2024 - Fix broken label issue (webkit only!)
- 01 Jun 2023 - Fix read-only styling to input, select and textarea. Fixes placeholder combobox.
- 23 May 2023 - Removed a11y default success message; Business requirement.
- 28 Apr 2023 - Fix safaris hard disable color override.
- 15 Feb 2023 - Combobox validation
- 18 Jan 2023 - Fix background-clip setting.
- 28 June 2022 - Fix scrollparent detector
- Make Safari (the new IE6) understand how parenthesis work when direction is rtl.
- Remove previous work around.
- Try to work around chrome mobile bug (1197882) where long datalists overlap keyboard.
- Fix chrome bug (674447, 849616) where datalist gets detached by scrolling.
- Wrapping of lang filenames in file field.
- PBS support: fix box-shadow on custom-control
- Regression: accent colors not picked up by sass.
- Allow re-enabled fields to validate.
- Remove file field blur validation.
- A11y: …show hidden span tag with this value”name of the file + “selected” add role=”alert”
- A11y: Redundantly add attribute
aria-required=true to elements with attribute required
- A11y: …add a hidden span tag with this value”name of the file + “uploaded” add role=”alert”
- Form Validation message not showing, when element hidden.
- IE11 premature error throwing.
- Better align custom indicators regardless font / line-height used.
- Remove background color IE11 from focused select.
Changed
- 09 Jan 2025 - feat(multiple-select): Show options with empty value.
- 30 Jun 2023 - Disabled state of checkbox/radio and switch.
Added
- 28 Aug 2024 - Add dynamic form fields example + added $.fn.viFormDynamicFieldsContainer() to assign to a dynamic fields container and keep validation in sync.
- 17 May 2023 - Form reset removes validation messages.
- 15 Mar 2023 - Allow browse button text to be changed.
- 15 Feb 2023 - Combobox reset
- 2 Dec 2022 - Add size sm size to text-fields.
- 14 Nov 2022 - Add data attribute
data-keyup to allow for keyup validation on a field. (required by wizard#contextual-fields)
- Add an example of a paragraph
- An example of labels on select fields.
- PBS support
- Examples of contextual form fields.
- Add
--top modifier to .custom-control for long labels.
- A11y: File field focus outline same as links.
- On submit focus on first invalid element
- Missing File Browser field
- RTL support
- Documentation
- Changed checkbox outline according new design input.
- Initial draft