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/

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