1

I have an otp input which looks like this :

enter image description here

html :

 <div id="divOuter">
                <div id="divInner">
                  <Grid.Row justify={"center"}>
                    <Grid.Col xs={12} md={8} lg={8}>
                      <TextField
                        padding={false}
                        background={`${t.INPUT_BGCOLOR}`}
                        id="otp"
                        autoFocusFlag={true}
                        // type={"number"}
                        top={true}
                        right={true}
                        margin={true}
                        required={true}
                        maxLength={4}
                        errWidth={true}
                        register={{
                          ...register("otp", {
                            required: true,
                            pattern: t.NumberOnlyPattern,
                          }),
                        }}
                        onChange={(e) => setValue("otp", e.target.value)}
                      />
                    </Grid.Col>
                  </Grid.Row>
                </div>

This is my input css :

 #divInner{
  left: 0;
  position: sticky;
}

#divOuter{
  zoom: 1.5;
  @media (max-width: ${(p) => p.theme.utils.toPx(p.theme.breakpoints.small)}) {
    zoom: 1.2;

  }

direction : ltr;
  padding-left: 15px;
  letter-spacing: 42px;
  border: 0;
  background-image: linear-gradient(to left,#edfaff 73%,rgba(255,255,255,0) 0%);
  background-position: bottom;
  background-size: 50px 1px;
  // background-repeat: repeat-x;
  background-position-x: 35px;
  width: 220px;
  min-width: 220px;

How can I add border around each input that the digit display in?

The background is background-image and if I add border it's set to the all inputs like this :

enter image description here

yanir midler
  • 2,153
  • 1
  • 4
  • 16
  • What do you mean by "OTP"? And please post your HTML **and** your CSS rule selectors. – Dai Dec 12 '21 at 11:07
  • an input that i enter otp that i send to the client : / .... – yanir midler Dec 12 '21 at 11:09
  • That still doesn't tell me what "OTP" stands for... do you mean "one-time passcode"? Also, **please post your HTML**. – Dai Dec 12 '21 at 11:11
  • yes. i added the html – yanir midler Dec 12 '21 at 11:16
  • What library or framework are you using? `` is not a standard HTML element. Also your CSS is invalid: `@media` rules cannot be defined _inside_ a rule, only outside it. Unless you're using SASS/SCSS/LESS? – Dai Dec 12 '21 at 11:20

1 Answers1

0

it's better that you use multiple inputs, one for each character or number in your OTP code, it's the solution in almost every good program out there,

like these two examples below:

example one

html:

<div class="prompt">
    Enter the code generated on your mobile device below to log in!
</div>

<form method="get" class="digit-group" data-group-name="digits" data-autosubmit="false" autocomplete="off">
    <input type="text" id="digit-1" name="digit-1" data-next="digit-2" />
    <input type="text" id="digit-2" name="digit-2" data-next="digit-3" data-previous="digit-1" />
    <input type="text" id="digit-3" name="digit-3" data-next="digit-4" data-previous="digit-2" />
    <span class="splitter">&ndash;</span>
    <input type="text" id="digit-4" name="digit-4" data-next="digit-5" data-previous="digit-3" />
    <input type="text" id="digit-5" name="digit-5" data-next="digit-6" data-previous="digit-4" />
    <input type="text" id="digit-6" name="digit-6" data-previous="digit-5" />
</form>

css:

@import url('https://fonts.googleapis.com/css?family=Raleway:200');

$BaseBG: #0f0f1a;

body, html {
    height: 100%;
    margin: 0;
    font-family: 'Raleway', sans-serif;
    font-weight: 200;
}

body {
    background-color: $BaseBG;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
}

.digit-group {
    input {
        width: 30px;
        height: 50px;
        background-color: lighten($BaseBG, 5%);
        border: none;
        line-height: 50px;
        text-align: center;
        font-size: 24px;
        font-family: 'Raleway', sans-serif;
        font-weight: 200;
        color: white;
        margin: 0 2px;
    }

    .splitter {
        padding: 0 5px;
        color: white;
        font-size: 24px;
    }
}

.prompt {
    margin-bottom: 20px;
    font-size: 20px;
    color: white;
}

js:

$('.digit-group').find('input').each(function() {
    $(this).attr('maxlength', 1);
    $(this).on('keyup', function(e) {
        var parent = $($(this).parent());
        
        if(e.keyCode === 8 || e.keyCode === 37) {
            var prev = parent.find('input#' + $(this).data('previous'));
            
            if(prev.length) {
                $(prev).select();
            }
        } else if((e.keyCode >= 48 && e.keyCode <= 57) || (e.keyCode >= 65 && e.keyCode <= 90) || (e.keyCode >= 96 && e.keyCode <= 105) || e.keyCode === 39) {
            var next = parent.find('input#' + $(this).data('next'));
            
            if(next.length) {
                $(next).select();
            } else {
                if(parent.data('autosubmit')) {
                    parent.submit();
                }
            }
        }
    });
});

or

example two

html:

<section class="container-fluid">
    <div class="row">
        <div class="col-md-8 offset-md-2">
            <form class="text-center">
                <div class="form-group">
                    <label for="password" class="text-white">Enter 4 Digit Password</label>
                    <div class="passcode-wrapper">
                        <input id="codeBox1" type="number" maxlength="1" onkeyup="onKeyUpEvent(1, event)" onfocus="onFocusEvent(1)">
                        <input id="codeBox2" type="number" maxlength="1" onkeyup="onKeyUpEvent(2, event)" onfocus="onFocusEvent(2)">
                        <input id="codeBox3" type="number" maxlength="1" onkeyup="onKeyUpEvent(3, event)" onfocus="onFocusEvent(3)">
                        <input id="codeBox4" type="number" maxlength="1" onkeyup="onKeyUpEvent(4, event)" onfocus="onFocusEvent(4)">
                    </div>
                </div>
            </form>
        </div>
    </div>
</section>

css:

// Body Styling only Begin ==============
body{text-align: center;background-color: lightcyan;font-family: 'POPPINS', Open-Sans;background: linear-gradient(to right, #4568dc, #b06ab3);}
::selection {color: #8e44ad;}
// Body Styling only End ================


// Container-fluid Styling only Begin ===
.container-fluid {
    .row {
        align-items: center;
        width: 100vw;
        height: 100vh;
    }
}
// Container-fluid Styling only End =====


// =====
// Passcode-wrapper Styling only Begin ==
.passcode-wrapper {
    display: flex;
    justify-content: space-between;
    align-items: center;
    width: auto;
    margin: 0 auto;
    input {
        width: 50px;
        height: 50px;
        padding: 0;
        margin-right: 5px;
        text-align: center;
        border: 1px solid gray;
        border-radius: 5px;
        &:last-child {
            margin-right: 0;
        }
        &::-webkit-inner-spin-button, 
        &::-webkit-outer-spin-button { 
            -webkit-appearance: none;
            appearance: none;
            margin: 0;
        }
        &:focus,
        &.focus {
            border-color: green;
            outline: none;
            box-shadow: none;
        }
    }
}
// Passcode-wrapper Styling only End ====

js:

function getCodeBoxElement(index) {
  return document.getElementById('codeBox' + index);
}
function onKeyUpEvent(index, event) {
  const eventCode = event.which || event.keyCode;
  if (getCodeBoxElement(index).value.length === 1) {
     if (index !== 4) {
        getCodeBoxElement(index+ 1).focus();
     } else {
        getCodeBoxElement(index).blur();
        // Submit code
        console.log('submit code ');
     }
  }
  if (eventCode === 8 && index !== 1) {
     getCodeBoxElement(index - 1).focus();
  }
}
function onFocusEvent(index) {
  for (item = 1; item < index; item++) {
     const currentElement = getCodeBoxElement(item);
     if (!currentElement.value) {
          currentElement.focus();
          break;
     }
  }
}

but if you insist on using only one input field you can use this solution, although it's not a good practice! and it does not put a border around each character, it just puts a line under each character

sima ghoreyshi
  • 379
  • 5
  • 21
  • 2
    "it's better that you use multiple inputs, one for each character or number in your OTP code" - I'm going to **strongly disagree** with that advice because it's impossible to _gracefully degrade_ with that arrangement. If JS and/or CSS is disabled or fails to load or anything else breaks it then users will have a horrid UX. – Dai Dec 14 '21 at 00:17
  • what would be a better solution for this question? because I`m seeing this almost everywhere, and the only browser that seems to have problem with modern js and css commands is IE which is obsolete, I would use one input with defined number of maximum characters and underlined each character for a better user experience but that wouldn't be the answer to this question, I think the main question here is how to get some defined length string from user where each character has a defined place and a border around itself – sima ghoreyshi Dec 14 '21 at 05:31
  • 1
    "what would be a better solution for this question?" - I'd have a single numeric `` which is displayed by default (for downlevel and broken clients) and use JS to hide it before the page renders (or after sanity-checks pass) and handle `'input'` events to update a set of (entirely-JS-controlled) `` elements for each digit entered. – Dai Dec 14 '21 at 05:34
  • 1
    The reason for wanting _graceful degradation_ with support for JS-less environments, even in modern web-browsers, is threefold: many of users actively disable JS entirely for security/privacy reasons (I think the Tor browser also disables JS by default too?), secondarily: lots of users have really awful and sloppily-written Chrome browser extensions that inject code into pages and break things (this happened to me last week!), and third: because an unhandled `throw` or other error inside the code-path will mean the rest of the code won't be run, which would also break the UX. – Dai Dec 14 '21 at 05:37
  • thank you for the complete and clear description, I've learned a better way from you, I wish you'd post it as an answer so I could mark it as useful answer – sima ghoreyshi Dec 14 '21 at 05:48
  • There's nothing stopping you from posting a second answer that uses the concept I just discussed. – Dai Dec 14 '21 at 05:49
  • Neither of the examples you linked to support pasting in a value, which is a dealbreaker for me. I need to be able to copy a code from a password manager and paste it in. – IanVS Jan 05 '22 at 22:58