Home » Html » HTML5 input required, scroll to input with fixed navbar on submit

HTML5 input required, scroll to input with fixed navbar on submit

Posted by: admin November 30, 2017 Leave a comment

Questions:

When trying to submit a form with missing required fields, my browser (Chrome), displays a message mentionning there is a field missing, and if it’s out of my screen, it scrolls up to it.

My problem is that I have a 50px fixed header in my webpage, and as a result, the input field is hidden, and the message seems to come out of nowhere:

Input field hidden

Instead of

Input field shown

Is there a way around this?

I tried both applying the 50px margin to <html> and to <body>

Cheers


EDIT

Here’s a fiddle of the problem: http://jsfiddle.net/LL5S6/1/

Answers:

The only way I found is adding an ‘override’ to the invalid handler.
To implement this for every input in your form you can do something like this.

var elements = document.querySelectorAll('input,select,textarea');
var invalidListener = function(){ this.scrollIntoView(false); };

for(var i = elements.length; i--;)
    elements[i].addEventListener('invalid', invalidListener);

This requires HTML5 and this is tested on IE11, Chrome and Firefox.
Credits to @HenryW for finding that scrollIntoView works like expected.

Note that the false parameter for scrollIntoView aligns the input with the bottom, so if you have a large form it may be aligned with the bottom of the page.

jsfiddle

Questions:
Answers:

I had the exact same problem and resolved it using jquery with this bit of code:

var delay = 0;
var offset = 150;

document.addEventListener('invalid', function(e){
   $(e.target).addClass("invalid");
   $('html, body').animate({scrollTop: $($(".invalid")[0]).offset().top - offset }, delay);
}, true);
document.addEventListener('change', function(e){
   $(e.target).removeClass("invalid")
}, true);

Offset should be the height of your header and delay is how long you want it to take to scroll to the element.

Questions:
Answers:

When there are several invalid inputs in the form, you only want to scroll to the first of them:

var form = $('#your-form')
var navbar = $('#your-fixed-navbar')

// listen for `invalid` events on all form inputs
form.find(':input').on('invalid', function (event) {
    var input = $(this)

    // the first invalid element in the form
    var first = form.find(':invalid').first()

    // only handle if this is the first invalid input
    if (input[0] === first[0]) {
        // height of the nav bar plus some padding
        var navbarHeight = navbar.height() + 50

        // the position to scroll to (accounting for the navbar)
        var elementOffset = input.offset().top - navbarHeight

        // the current scroll position (accounting for the navbar)
        var pageOffset = window.pageYOffset - navbarHeight

        // don't scroll if the element is already in view
        if (elementOffset > pageOffset && elementOffset < pageOffset + window.innerHeight) {
            return true
        }

        // note: avoid using animate, as it prevents the validation message displaying correctly
        $('html,body').scrollTop(elementOffset)
    }
})

JSFiddle

Questions:
Answers:

ok, i did a dirty test with a code snippet i found here on SO

As it is a code from someone else, i just alter it to scroll to the element that had a missing input requirement.
I do not want any credit for it, and it maybe is not even what you have in mind, you or someone else could use it as a reference.

The goal was to get the id of the forgotten/wrong input element:

            var myelement = input.id;
            var el = document.getElementById(myelement);
            el.scrollIntoView(false);

Please keep in mind that this fiddle only works for your posted fiddle above, it not handles multiple forgotten or wrong input fields.I only wanted to show an alternative.

—–>jSFiddle

Questions:
Answers:

Two solutions:

  • One: apply padding to the body –>

    body {
     padding-top:50px;
    }
    
  • Two : apply margin to the main container –>

     #content {
       margin-top:50px;
     }