Skip to content

Forms

createPal({ watch: 'form#signup' }); // at creation
pal.watch('form#checkout'); // or later; returns an unwatch function

watch accepts a selector or an element, and the element can be a form or any container of forms. A selector also matches forms rendered after you call watch(), which suits single-page apps. To watch several, pass an array: watch: ['#signup', '#newsletter'].

SituationReaction
A field fails native validation (invalid event)wince, and it turns to look at the first bad field
A field gets aria-invalid="true"wince and look at it
Required fields become validcheeks warm up; wink when they’re all valid
The form is submitted with no invalid fieldscheer
Submitted with an invalid field (e.g. novalidate forms)wince instead

Try both kinds of validation. Mood: neutral

Native validation works as-is. For JavaScript validation, pagepal watches aria-invalid, which accessible forms set on invalid fields anyway:

  • MUI, Chakra UI, Mantine and most component libraries set it for you.
  • React Hook Form, Formik: pass it yourself, which also helps screen reader users:
<input {...register('email')} aria-invalid={errors.email ? 'true' : 'false'} />

A successful submit isn’t always a successful save. Turn the automatic cheer off and cheer yourself:

pal.watch('form#checkout', { cheer: false });
const res = await fetch('/api/orders', { method: 'POST', body });
if (res.ok) pal.react('cheer');
pal.watch(target, {
cheer: true, // cheer on a valid submit
wince: true, // wince (and look) on validation errors
progress: true, // warm up as required fields fill in; wink when complete
});

Looking at the bad field is controlled by the pal-level gaze option: gaze: false turns it off, and gaze: { duration: 2500 } sets how long it looks.

Forms emit events you can use directly or feed to analytics:

pal.on('formError', ({ form, field, source, validity }) => {}); // validity: 'valueMissing', 'typeMismatch', …
pal.on('formSubmit', ({ form, success }) => {});
pal.on('formProgress', ({ form, field, progress }) => {}); // progress: 0..1, or null without required fields

The pal in the corner is pagepal itself.