Navigate focus by setting tabindexes

How do you automatically change focus to the next input box after user enters the maximum character length by setting the tab index

You’ll want to use JavaScript for that. This post on SO should help.

1 Like

Hm I’d rather not go with those solutions TBH… they’re all suggesting to listen to key events, which would also prevent you from using tab, shift and arrow keys once the max length is reached… not to mention they’re hard-coding the max lengths in the JS, rather than setting the actual maxlength attribute. Using jQuery, of course.

So here’s a simple generic solution, that also should not conflict with keyboard navigation:

<input type="text" maxlength="3" class="auto-focus-next">
<input type="text" maxlength="5" class="auto-focus-next">
<input type="text" maxlength="2" class="auto-focus-next">
function initAutoFocus (input, index, list) {
  const next = list[index + 1]

  if (!next) {
    return
  }

  input.addEventListener('input', () => {
    if (input.value.length === input.maxLength) {
      next.focus()
    }
  })
}

document
  .querySelectorAll('.auto-focus-next')
  .forEach(initAutoFocus)
3 Likes

So what would be the CSS properties to go with the class, auto-focus-next

There is no CSS required here, the purpose of those classes is merely to apply the behaviour in the JS. If it should apply to all input elements with a max length, you might as well use that for the selector though:

document
  .querySelectorAll('[maxlength]')
  .forEach(initAutoFocus)

Here’s a pen:

2 Likes

Ok. Thanks

Can you resize this input box?
Thanks

Sure.

Can you show me how to change the properties on this input box, I can’t get it to change from the default long rectangular box. I applied height and width.
Thanks

Now this is just CSS really:

CSS

.small-input {
  width: 42px;
}

HTML

<input class="small-input">

What if each of the input boxes in post#4 had a letter in it and it was supposed to spell a word, if right display a checkmark and a message, say “bed” if wrong display a “x”; how would I do that?
Thanks

Does that mean that you expect each of the input boxes from Post #4 to have a maxlength of one character each, instead of having different maxlengths of 3, 5, and 2?

In that case, you’ll want an input event that gets the values from each input box, and when all of them are filled in it shows either a :white_check_mark: or a :x:

Here’s the code that achieves that.

function documentInputHandler(evt) {
  const fields = document.querySelectorAll('.auto-focus-next');
  const values = Array.from(fields).map(f => f.value).filter(v => v);
  if (values.length < fields.length) {
  	return;
  }
  document.querySelector("#result").innerHTML = (
      values.join("") === "bed" ? "✅" : "❌"
  );
}
document.addEventListener("input", documentInputHandler);

You can see the code working at https://jsfiddle.net/kp43f5yL/

https://jsfiddle.net/kp43f5yL/1/

Yes, each input box will have a wavelength of 1,but there will be more results than “bed”

Sorry maxlength

If you just want to check if each input is filled, you can add a required attribute:

<input maxlength="1" required class="auto-focus-next">

This will show an error message for missing values when you try to submit the form, but you can also customise how to report that error using CSS and / or JS:

Right now it seems that we’re trying to build a platypus from descriptions of different types of creatures.

It would be really helpful to get a full description of what is wanted.

3 Likes

Well I was just reading all the different codes, haven’t tried them yet, but as for a description, what I have is three input boxes “bed”, as in post #12 to validate when the user enters data;it will either be right or wrong (check, if right or x if wrong). If check,there will be a message displayed .There will be more input words to validate besides “bed”.
In your post#13…values.join…===bed
Do you need this statement for each word? Hope this makes sense😀

Three input boxes each with a letter in it, a sample word of “bed” which is three letters, so one letter per box, which is why the auto-advance to the next box.

Each box contains no more than a single letter. That is the shape of my elephant.

Going with @Paul_Wilkins’ solution you might define a list of valid words, and check if the joined values are in that list:

const WORDS = ['foo', 'bar', 'baz']

// ...
document.querySelector('#result').innerHTML = (
  WORDS.includes(values.join('')) ? '✅' : '❌'
)

Another possibility would be to define a pattern on a parent fieldset as a data attribute, mimicking the pattern constraint validtation so that you don’t have to maintain a hard-coded list of valid words in your JS:

CSS

.error {
  display: none;
}

.invalid {
  border: 1px solid red;
}

.invalid .error {
  display: block;
}

HTML

<fieldset data-pattern="foo|bar|baz">
  <input type="text" maxlength="1" class="auto-focus-next">
  <input type="text" maxlength="1" class="auto-focus-next">
  <input type="text" maxlength="1" class="auto-focus-next">
  <p class="error">pattern mismatch</p>
</fieldset>

JS

function validatePattern (event) {
  const fieldset = event.currentTarget
  const pattern = new RegExp(fieldset.dataset.pattern)

  const value = Array.from(
    fieldset.elements,
    element => element.value
  ).join('')

  fieldset.classList.toggle(
    'invalid',
    !pattern.test(value)
  )
}

document
  .querySelectorAll('[data-pattern]')
  .forEach(element => {
    element.addEventListener('change', validatePattern)
  })

Thanks