I’m not sure I totally understand your objective but from the demo I can see that you maybe have a long form with a lot of inputs and you want to scroll back to the input with an alert, you can accomplish that with JavaScript easily using
But I also think you want to use the browser’s default validation, so this is how to detect the input that has an invalid value, and scroll to it.
const element = document.getElementById("element");
submitButton.addEventListener("click", function (event) {
if (element.validity.typeMismatch) {
// scroll to the invalid input
document.querySelector(element).scrollIntoView({behavior: "smooth"});
// Show a custom Error/Warning
email.setCustomValidity("You need to fill this !!?!");
} else {
email.setCustomValidity("");
}
});
if that’s what you want, then I advice you to stay away from CSS and stick with JavaScript, you can also check the DOM Object ValidityState that is accessible through element.validity, it has all the browser’s defalut validation info you need.
you can also read Client-side form validation and Element.scrollIntoView()
EDIT:
@ViktorG is right, scrollIntoView() would never get the job done without some complex trick, but we can still use the normal scroll and prevent the default browser behavior while making use of the browser’s alerts using reportValidity(), sadly it’s not possible to use preventDefault() just on the scroll and keeping the alert since it doesn’t take parameters.
the snippet demo is working good enough but ofc you need to tweak it to fit your desired result.
const el = e => document.querySelector(e),
ela = e => document.querySelectorAll(e),
btn = el('#btn');
btn.addEventListener('click', () => {
let len = ela('form input').length - 1; // -1 is meant to stop before we reach the button, if you're using button then remove it
for (let i = 0; i < len; i++) {
if (!el('form')[i].checkValidity()) {
event.preventDefault();
/*
* We're scrolling to the element position - the header height * 2, to always make the element visible.
* */
window.scroll({
top: el('#input').offsetTop - (el('header').scrollHeight * 2),
behavior: "smooth"
});
/*
* The Delay is meant to prevent reportValidity() from scrolling till the first scrolling fase is done.
* */
setTimeout(() => {
el('form')[i].reportValidity(); // we manually trigger the browser's validation
}, 800);
break; // we break because we only show one alert at a time
}
}
});
I have a problem with native inputs of type date. My case consists of a native form with multiple native inputs of different types (text, number, date, etc.) The application featuring the form has a sticky header which results in the following behaviour:
Whenever the form is submitted and the form validation encounters an invalid input for an input field, the form automatically scrolls so that the affected field shows up at the very top of the browser, while showing the validation error message. This field is obscured by the sticky header.
I solved this problem by using the scroll-margin CSS property for the input fields, which respects the height of the sticky header.
This works great for all input types, except for date input fields.
I was not able to find any official bug reports.
Has anyone else encountered this behaviour? If so, how could I fix this, without the use of JQuery?
Apply scroll-margin to an element wrapping these input fields instead?
Comment posted by ViktorG
@CBroe I tried wrapping the element in a
Comment posted by ViktorG
@CBroe Added a codepen example
Comment posted by CBroe
Yeah, can reproduce the issue. Guess you’ll have to file a bug report then, since applying it to a wrapper element indeed does not seem to help.
Comment posted by ViktorG
@CBroe you are correct, it also does not work in Chromium-based browsers… I had a bug in my application which made me think otherwise. I edited the question. I was also experimenting with the
Comment posted by jadinerky
NOTE: my answer is based of :invalid in general so you can even use it as an event, like:
Comment posted by ViktorG
Thanks for your response. I tried to implement your approach into the code example that I provided and it resulted in the same behaviour as described in the question. Could you provide a working code example?
Comment posted by jsfiddle.net/2so36hyz
Based on @hassan-aoutof answer I made a working demo although ScrollIntoView did not work with a margin top so I used a custom function to get the dimensions and scroll via window.scrollTo method.
Comment posted by jadinerky
@ViktorG, i added a working example, sadly it wasn’t as small as i was hoping because i was forced to use