Skip to content

Form validation

Describe your rules, validate your data, then show the messages in your own UI. The helper leaves you in control of when validation runs and how errors appear.

validate(data, schema, customRules?) is a synchronous helper, not a form controller. Import it from @jnreis/briojs/forms or @jnreis/briojs; the optional brio.forms.min.js browser script exposes brio.validate.

import { validate } from '@jnreis/briojs/forms';
const schema = {
email: [
{ name: 'required', message: 'Enter your email address.' },
{ name: 'email', message: 'Enter a valid email address.' },
],
password: [{ name: 'min', value: 8, message: 'Use at least eight characters.' }],
confirmation: [{ name: 'same', value: 'password', message: 'Passwords must match.' }],
};
const result = validate({
email: 'ada@example.com',
password: 'eight-or-more',
confirmation: 'eight-or-more',
}, schema);
if (result !== true) {
// Field names map to arrays of messages, e.g. result.email.
console.log(result);
}
ResultMeaning
trueAll rules passed.
Field-to-message-array objectValidation failed; each field may have several messages.

Check result !== true, not truthiness: an error object is truthy too.

All declared rules run in order. Each rule accepts { name, value?, message? }. Without a custom message, the fallback is "<field> failed <rule> validation".

RuleMeaning
requiredRejects null, undefined, false, empty/whitespace-only strings, empty arrays, and objects without enumerable string keys. Numeric zero is valid.
min / maxMinimum/maximum string or array length, or numeric value. The rule’s value supplies the bound. String length is UTF-16 length, not grapheme count.
emailA basic string email-format check, not verification that an address exists or can receive mail.
sameStrict equality with another top-level field named by value.
inMembership in the array supplied as value, using native includes semantics.

Custom rules receive (value, ruleValue, allData) and return a boolean. They can add rules or override built-ins:

const result = validate({ age: 24 }, {
age: [{ name: 'multipleOf', value: 3, message: 'Use a multiple of three.' }],
}, {
multipleOf: (value, divisor) => typeof value === 'number' && value % Number(divisor) === 0,
});

Unknown rule names throw a TypeError; they are not skipped. There is no implicit trimming, type coercion of field values, nested-path traversal, async validation, or automatic DOM error rendering. For an optional field, omit format rules when it is empty rather than expecting email or min to skip it. Call validation from your own submit/input handlers, put errors in reactive state, and render messages with b-text. If using novalidate to replace native form validation, provide your own accessible messages and focus handling. Server-side validation is still required.