Skip to content
Advertisement

Text flows out of input after next event is fired if input is focued

While building a basic application, when I click a button, the text inside my currently focused input overflows only in Chrome. However, that text can be accessed using (right) arrow key(s). Is there any way to avoid this? I tried clipboard copy-paste but that did not work.

const peopleElem = document.querySelector("#people");
const billElem = document.querySelector("#bill");
const submit = document.querySelector("[type="submit"]");
const form = document.querySelector("form");
const tipPerPersonElem = document.querySelector("[data-tip-person]");
const totalPerPersonElem = document.querySelector("[data-total-person]");
let billError = peopleError = false;

class TipCalc {
  constructor() {
    this.tipPerPerson = 0;
    this.totalPerPerson = 0;
    this.tip = 0
    this.tipPercent = 0;
    this.bill = parseFloat(billElem.value);
    this.people = parseFloat(peopleElem.value);
  }

  getTip() {
    const element = document.querySelector(".active");
    if (!element) return 0;
    if (element.tagName === "BUTTON") return this.tipPercent = element.innerText.replace("%", "");
    return this.tipPercent = element.value.replace("%", "");
  }

  getTipPerPerson() {
    this.getTip();
    this.tip = ((this.tipPercent / 100) * this.bill);
    this.tipPerPerson = this.tip / this.people;
    return this.tipPerPerson;
  }

  getTotalPerPerson() {
    this.getTipPerPerson();
    this.totalPerPerson = (this.bill + this.tip) / this.people
    return this.totalPerPerson;
  }
}

const tipOptions = [...document.querySelectorAll("button"), document.querySelector("#custom")];
tipOptions.forEach(option => {
  if (option.tagName === "INPUT" && option.value.length) option.addEventListener("keyup", () => {
    tipOptions.forEach(option => option.classList.remove("active"));
    option.classList.toggle("active");
  })
  if (!(option.type == "submit")) option.addEventListener("click", () => {
    tipOptions.forEach(option => option.classList.remove("active"));
    option.classList.toggle("active");
  })
})

form.addEventListener("submit", event => {
  event.preventDefault();
  checkInputForError(peopleElem, peopleError, true);
  checkInputForError(billElem, billError, false);
  if (billError || peopleError) return;
  const tipCalculator = new TipCalc();
  const tip = isNaN(tipCalculator.getTipPerPerson()) ? 0 : tipCalculator.getTipPerPerson();
  const total = isNaN(tipCalculator.getTotalPerPerson()) ? 0 : tipCalculator.getTotalPerPerson();
  const formatter = new Intl.NumberFormat(undefined, {
    style: "currency",
    currency: "USD",
    signDisplay: "never"
  });
  tipPerPersonElem.innerText = formatter.format(tip);
  totalPerPersonElem.innerText = formatter.format(total);
  submit.style.display = "none";
  const resetBtn = document.querySelector("[type="reset"]");
  resetBtn.style.display = "block";
  resetBtn.addEventListener("click", () => {
    reset()
    resetBtn.style.display = "none";
    submit.style.display = "block";
  })
})

document.addEventListener("DOMContentLoaded", () => {
  reset()
})

peopleElem.addEventListener("keyup", () => checkInputForError(peopleElem, peopleError, true));
billElem.addEventListener("keyup", () => checkInputForError(billElem, billError, false));

function checkInputForError(input, error, showError) {
  const value = input.value.trim() || 0;
  if (!value || isNaN(parseFloat(value)) || parseFloat(value) == 0) {
    if (showError) document.querySelector(".warning").style.display = "inline";
    input.classList.add("error");
    error = true;
  } else {
    if (showError) document.querySelector(".warning").style.display = "none";
    input.classList.remove("error");
    input.classList.add("correct");
    error = false;
  }
}

function reset(submit = false) {
  const tipPerPersonElem = document.querySelector("[data-tip-person]");
  const totalPerPersonElem = document.querySelector("[data-total-person]");
  tipPerPersonElem.innerText = "";
  totalPerPersonElem.innerText = "";
  console.log(tipPerPersonElem.innerText, totalPerPersonElem.innerText, "reset", submit);
  tipOptions.forEach(option => option.classList.remove("active"));
  document.querySelectorAll("input").forEach(input => {
    input.classList.remove("correct");
    input.classList.remove("error");
    input.value = "";
  })
}
:root {
  --primary-color: hsl(172, 67%, 45%);
  --very-dark-cyan: hsl(183, 100%, 15%);
  --dark-grayish-cyan: hsl(186, 14%, 43%);
  --grayish-cyan: hsl(184, 14%, 56%);
  --light-grayish-cyan: hsl(185, 41%, 84%);
  --very-light-grayish-cyan: hsl(189, 41%, 97%);
  --white: hsl(0, 0%, 100%);
  --primary-font-size: 24px;
  --primary-font-family: 'Space Mono', monospace;
}


/* GLOABAL TAGS */

body {
  width: 100%;
  margin: 0;
  overflow: hidden;
  font-family: var(--primary-font-family);
  background-color: var(--light-grayish-cyan);
}

header {
  text-align: center;
}

h1 {
  color: var(--very-dark-cyan);
  margin-top: 0;
  text-transform: uppercase;
}

h1 span {
  display: block;
  margin: 0;
}

label {
  display: block;
  text-transform: capitalize;
}

button {
  outline: none;
  border: none;
  text-align: center;
  background-color: var(--very-dark-cyan);
  font-size: var(--primary-font-size);
  color: var(--white);
  text-transform: capitalize;
  margin: 8px;
  padding-top: 8px;
  padding-bottom: 8px;
  border-radius: 4px;
  cursor: pointer;
}

legend {
  margin-bottom: 8px;
}


/* Chrome,
Safari,
Edge, */


/* Opera  */

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}


/* Firefox */

input[type=number] {
  -moz-appearance: textfield;
}

input {
  display: block;
  border: none;
  background-color: var(--very-light-grayish-cyan);
  font-size: var(--primary-font-size);
  height: 30px;
  color: var(--very-dark-cyan);
  background-repeat: no-repeat;
  background-position: left center;
}

input:not(#custom) {
  text-indent: 99.8%;
}

aside {
  font-size: 11px;
  text-align: center;
}

aside a {
  color: hsl(228, 45%, 44%);
}


/* END OF GLOBAL TAGS GENERIC IDs  */

#bill {
  background-image: url('https://kaustubhmaladkar.github.io/Tip-Calculator/images/icon-dollar.svg');
}

#people {
  background-image: url('https://kaustubhmaladkar.github.io/Tip-Calculator/images/icon-person.svg');
}


/* END OF GENERIC IDs GENERIC CLASSES*/

button,
#custom {
  width: calc(50% - 20px);
  font-weight: bold;
}


/* END OF GENERIC CLASSES  */


/* INPUT  */

.input {
  background-color: var(--white);
  color: var(--dark-grayish-cyan);
  border-top-right-radius: 20px;
  border-top-left-radius: 20px;
  margin-top: 20px;
  padding-bottom: 30px;
}

.input legend {
  margin-top: 20px;
  margin-left: 20px;
}

legend:nth-of-type(2) label {
  width: 100%;
}

legend:nth-of-type(2) {
  display: flex;
  flex-wrap: wrap;
}

[for="people"] {
  display: inline;
}

.warning {
  display: none;
  /* margin-left: 92px; */
  color: red;
  font-size: 12px;
  background-color: transparent;
}

input#custom {
  background-color: var(--white);
  color: var(--dark-grayish-cyan);
  margin-top: 12px;
  margin-left: 2px;
  padding-bottom: 8px;
  opacity: 1;
}

input#custom::placeholder {
  text-transform: capitalize;
  color: var(--dark-grayish-cyan);
  opacity: 1;
}


/* END OF INPUT */


/*OUTPUT*/

.output {
  background-color: var(--very-dark-cyan);
  display: flex;
  margin-top: -8px;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  border-radius: 10px;
}

.output div,
.output span {
  width: 100%;
}

.output>div>div {
  display: flex;
  gap: 15px;
}

.output>div>div:first-of-type {
  margin-top: 30px;
  margin-bottom: 15px;
}

.output>div>div:last-of-type {
  margin-top: 15px;
  margin-bottom: 30px;
}

[type="submit"],
[type="reset"] {
  font-family: var(--primary-font-family);
  background-color: var(--primary-color);
  width: 90%;
  text-align: center;
  color: var(--very-dark-cyan);
}

.tip-person,
.total-person {
  font-size: 35px;
  color: var(--primary-color);
}

.output>div>div>div>span:first-of-type {
  text-transform: capitalize;
  color: var(--white);
  display: block;
}

.output>div>div>div>span:last-of-type {
  color: var(--grayish-cyan);
}


/*END OF OUTPUT */

.active:not(input) {
  background-color: var(--primary-color);
  color: var(--very-dark-cyan);
  transition: background 0.7s ease-in-out;
}

.correct {
  border: lightgreen 2px solid;
}

.error {
  border: red 2px solid;
}

.correct:focus,
.error:focus {
  outline: none;
}


/* JAVASCRIPT CLASSES */


/* END OF JAVASCRIPT CLASSES */


/* FOR DESKTOP   */

@media (min-width: 1200px) {
  /* RESET */
  html,
  body,
  main {
    margin: 0;
  }
  /* END OF RESET */
  /* GENERIC TAGS */
  form {
    width: 100%;
    max-width: 900px;
    border-radius: 15px;
    overflow: hidden;
    margin: auto;
    padding-right: 15px;
    display: flex;
    width: fit-content;
    background-color: var(--white);
  }
  input {
    width: 90%;
  }
  aside {
    display: none;
  }
  /* END OF GENERIC TAGS */
  /* GENERIC CLASSES */
  .output,
  .input {
    height: 400px;
  }
  .warning {
    margin-left: 92px;
  }
  /* END OF GENERIC CLASSES */
  /* INPUT */
  .input button,
  .input input#custom {
    width: calc(100% / 3 - 20px);
  }
  .input {
    width: 50%;
    padding-bottom: 0;
  }
  .input legend {
    margin-left: 25px;
  }
  /* END OF INPUT */
  /* OUTPUT */
  .output {
    width: 50%;
    margin: 22px;
    padding: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
  }
  .output div {
    margin-left: 20px;
  }
  .output>div>div:first-of-type {
    margin-top: -20px;
    margin-bottom: 40px;
  }
  [type="reset"] {
    display: none;
  }
  /* END OF OUTPUT */
}
<h1>
  <span>spli</span>
  <span>tter</span>
</h1>

<form action="post">
  <div class="input">
    <legend>
      <label for="bill">bill</label>
      <input type="number" name="bill" id="bill" class="correct">
    </legend>
    
    <legend>
      <label for="custom">select tip %</label>
      <button type="button">5%</button>
      <button type="button" class="">10%</button>
      <button type="button">15%</button>
      <button type="button">25%</button>
      <button type="button">50%</button>
      <input placeholder="custom" name="custom" id="custom" class="">
    </legend>
    
    <legend>
      <label for="people">Number of People</label>
      <p class="warning" style="display: inline;">Can't be zero</p>
      <input type="number" name="people" id="people" class="">
    </legend>
  </div>
  
  <div class="output">
    <div>
      <div>
        <div>
          <span>tip amount</span>
          <span>/ person</span>
        </div>
        
        <span class="tip-person" data-tip-person=""></span>
      </div>
      
      <div>
        <div>
          <span>Total</span>
          <span>/ person</span>
        </div>
        
        <span class="total-person" data-total-person=""></span>
      </div>
    </div>
    
    <button type="submit" style="display: block;">Calculate</button>
    <button type="reset" class="" style="display: none;">Reset</button>
  </div>
</form>

Live site: https://kaustubhmaladkar.github.io/Tip-Calculator/

Code on Github: https://github.com/KaustubhMaladkar/Tip-Calculator/

Advertisement

Answer

The problem comes from this line:

input:not(#custom) {
  text-indent: 99.8%;
}

If you only want a alignment to the right, change it to:

input:not(#custom) {
  text-align: right;
}

Working example:

const peopleElem = document.querySelector("#people");
const billElem = document.querySelector("#bill");
const submit = document.querySelector("[type="submit"]");
const form = document.querySelector("form");
const tipPerPersonElem = document.querySelector("[data-tip-person]");
const totalPerPersonElem = document.querySelector("[data-total-person]");
let billError = peopleError = false;

class TipCalc {
  constructor() {
    this.tipPerPerson = 0;
    this.totalPerPerson = 0;
    this.tip = 0
    this.tipPercent = 0;
    this.bill = parseFloat(billElem.value);
    this.people = parseFloat(peopleElem.value);
  }

  getTip() {
    const element = document.querySelector(".active");
    if (!element) return 0;
    if (element.tagName === "BUTTON") return this.tipPercent = element.innerText.replace("%", "");
    return this.tipPercent = element.value.replace("%", "");
  }

  getTipPerPerson() {
    this.getTip();
    this.tip = ((this.tipPercent / 100) * this.bill);
    this.tipPerPerson = this.tip / this.people;
    return this.tipPerPerson;
  }

  getTotalPerPerson() {
    this.getTipPerPerson();
    this.totalPerPerson = (this.bill + this.tip) / this.people
    return this.totalPerPerson;
  }
}

const tipOptions = [...document.querySelectorAll("button"), document.querySelector("#custom")];
tipOptions.forEach(option => {
  if (option.tagName === "INPUT" && option.value.length) option.addEventListener("keyup", () => {
    tipOptions.forEach(option => option.classList.remove("active"));
    option.classList.toggle("active");
  })
  if (!(option.type == "submit")) option.addEventListener("click", () => {
    tipOptions.forEach(option => option.classList.remove("active"));
    option.classList.toggle("active");
  })
})

form.addEventListener("submit", event => {
  event.preventDefault();
  checkInputForError(peopleElem, peopleError, true);
  checkInputForError(billElem, billError, false);
  if (billError || peopleError) return;
  const tipCalculator = new TipCalc();
  const tip = isNaN(tipCalculator.getTipPerPerson()) ? 0 : tipCalculator.getTipPerPerson();
  const total = isNaN(tipCalculator.getTotalPerPerson()) ? 0 : tipCalculator.getTotalPerPerson();
  const formatter = new Intl.NumberFormat(undefined, {
    style: "currency",
    currency: "USD",
    signDisplay: "never"
  });
  tipPerPersonElem.innerText = formatter.format(tip);
  totalPerPersonElem.innerText = formatter.format(total);
  submit.style.display = "none";
  const resetBtn = document.querySelector("[type="reset"]");
  resetBtn.style.display = "block";
  resetBtn.addEventListener("click", () => {
    reset()
    resetBtn.style.display = "none";
    submit.style.display = "block";
  })
})

document.addEventListener("DOMContentLoaded", () => {
  reset()
})

peopleElem.addEventListener("keyup", () => checkInputForError(peopleElem, peopleError, true));
billElem.addEventListener("keyup", () => checkInputForError(billElem, billError, false));

function checkInputForError(input, error, showError) {
  const value = input.value.trim() || 0;
  if (!value || isNaN(parseFloat(value)) || parseFloat(value) == 0) {
    if (showError) document.querySelector(".warning").style.display = "inline";
    input.classList.add("error");
    error = true;
  } else {
    if (showError) document.querySelector(".warning").style.display = "none";
    input.classList.remove("error");
    input.classList.add("correct");
    error = false;
  }
}

function reset(submit = false) {
  const tipPerPersonElem = document.querySelector("[data-tip-person]");
  const totalPerPersonElem = document.querySelector("[data-total-person]");
  tipPerPersonElem.innerText = "";
  totalPerPersonElem.innerText = "";
  console.log(tipPerPersonElem.innerText, totalPerPersonElem.innerText, "reset", submit);
  tipOptions.forEach(option => option.classList.remove("active"));
  document.querySelectorAll("input").forEach(input => {
    input.classList.remove("correct");
    input.classList.remove("error");
    input.value = "";
  })
}
:root {
  --primary-color: hsl(172, 67%, 45%);
  --very-dark-cyan: hsl(183, 100%, 15%);
  --dark-grayish-cyan: hsl(186, 14%, 43%);
  --grayish-cyan: hsl(184, 14%, 56%);
  --light-grayish-cyan: hsl(185, 41%, 84%);
  --very-light-grayish-cyan: hsl(189, 41%, 97%);
  --white: hsl(0, 0%, 100%);
  --primary-font-size: 24px;
  --primary-font-family: 'Space Mono', monospace;
}


/* GLOABAL TAGS */

body {
  width: 100%;
  margin: 0;
  overflow: hidden;
  font-family: var(--primary-font-family);
  background-color: var(--light-grayish-cyan);
}

header {
  text-align: center;
}

h1 {
  color: var(--very-dark-cyan);
  margin-top: 0;
  text-transform: uppercase;
}

h1 span {
  display: block;
  margin: 0;
}

label {
  display: block;
  text-transform: capitalize;
}

button {
  outline: none;
  border: none;
  text-align: center;
  background-color: var(--very-dark-cyan);
  font-size: var(--primary-font-size);
  color: var(--white);
  text-transform: capitalize;
  margin: 8px;
  padding-top: 8px;
  padding-bottom: 8px;
  border-radius: 4px;
  cursor: pointer;
}

legend {
  margin-bottom: 8px;
}


/* Chrome,
Safari,
Edge, */


/* Opera  */

input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}


/* Firefox */

input[type=number] {
  -moz-appearance: textfield;
}

input {
  display: block;
  border: none;
  background-color: var(--very-light-grayish-cyan);
  font-size: var(--primary-font-size);
  height: 30px;
  color: var(--very-dark-cyan);
  background-repeat: no-repeat;
  background-position: left center;
}

input:not(#custom) {
  text-align: right;
}

aside {
  font-size: 11px;
  text-align: center;
}

aside a {
  color: hsl(228, 45%, 44%);
}


/* END OF GLOBAL TAGS GENERIC IDs  */

#bill {
  background-image: url('https://kaustubhmaladkar.github.io/Tip-Calculator/images/icon-dollar.svg');
}

#people {
  background-image: url('https://kaustubhmaladkar.github.io/Tip-Calculator/images/icon-person.svg');
}


/* END OF GENERIC IDs GENERIC CLASSES*/

button,
#custom {
  width: calc(50% - 20px);
  font-weight: bold;
}


/* END OF GENERIC CLASSES  */


/* INPUT  */

.input {
  background-color: var(--white);
  color: var(--dark-grayish-cyan);
  border-top-right-radius: 20px;
  border-top-left-radius: 20px;
  margin-top: 20px;
  padding-bottom: 30px;
}

.input legend {
  margin-top: 20px;
  margin-left: 20px;
}

legend:nth-of-type(2) label {
  width: 100%;
}

legend:nth-of-type(2) {
  display: flex;
  flex-wrap: wrap;
}

[for="people"] {
  display: inline;
}

.warning {
  display: none;
  /* margin-left: 92px; */
  color: red;
  font-size: 12px;
  background-color: transparent;
}

input#custom {
  background-color: var(--white);
  color: var(--dark-grayish-cyan);
  margin-top: 12px;
  margin-left: 2px;
  padding-bottom: 8px;
  opacity: 1;
}

input#custom::placeholder {
  text-transform: capitalize;
  color: var(--dark-grayish-cyan);
  opacity: 1;
}


/* END OF INPUT */


/*OUTPUT*/

.output {
  background-color: var(--very-dark-cyan);
  display: flex;
  margin-top: -8px;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  border-radius: 10px;
}

.output div,
.output span {
  width: 100%;
}

.output>div>div {
  display: flex;
  gap: 15px;
}

.output>div>div:first-of-type {
  margin-top: 30px;
  margin-bottom: 15px;
}

.output>div>div:last-of-type {
  margin-top: 15px;
  margin-bottom: 30px;
}

[type="submit"],
[type="reset"] {
  font-family: var(--primary-font-family);
  background-color: var(--primary-color);
  width: 90%;
  text-align: center;
  color: var(--very-dark-cyan);
}

.tip-person,
.total-person {
  font-size: 35px;
  color: var(--primary-color);
}

.output>div>div>div>span:first-of-type {
  text-transform: capitalize;
  color: var(--white);
  display: block;
}

.output>div>div>div>span:last-of-type {
  color: var(--grayish-cyan);
}


/*END OF OUTPUT */

.active:not(input) {
  background-color: var(--primary-color);
  color: var(--very-dark-cyan);
  transition: background 0.7s ease-in-out;
}

.correct {
  border: lightgreen 2px solid;
}

.error {
  border: red 2px solid;
}

.correct:focus,
.error:focus {
  outline: none;
}


/* JAVASCRIPT CLASSES */


/* END OF JAVASCRIPT CLASSES */


/* FOR DESKTOP   */

@media (min-width: 1200px) {
  /* RESET */
  html,
  body,
  main {
    margin: 0;
  }
  /* END OF RESET */
  /* GENERIC TAGS */
  form {
    width: 100%;
    max-width: 900px;
    border-radius: 15px;
    overflow: hidden;
    margin: auto;
    padding-right: 15px;
    display: flex;
    width: fit-content;
    background-color: var(--white);
  }
  input {
    width: 90%;
  }
  aside {
    display: none;
  }
  /* END OF GENERIC TAGS */
  /* GENERIC CLASSES */
  .output,
  .input {
    height: 400px;
  }
  .warning {
    margin-left: 92px;
  }
  /* END OF GENERIC CLASSES */
  /* INPUT */
  .input button,
  .input input#custom {
    width: calc(100% / 3 - 20px);
  }
  .input {
    width: 50%;
    padding-bottom: 0;
  }
  .input legend {
    margin-left: 25px;
  }
  /* END OF INPUT */
  /* OUTPUT */
  .output {
    width: 50%;
    margin: 22px;
    padding: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-around;
  }
  .output div {
    margin-left: 20px;
  }
  .output>div>div:first-of-type {
    margin-top: -20px;
    margin-bottom: 40px;
  }
  [type="reset"] {
    display: none;
  }
  /* END OF OUTPUT */
}
<h1>
  <span>spli</span>
  <span>tter</span>
</h1>

<form action="post">
  <div class="input">
    <legend>
      <label for="bill">bill</label>
      <input type="number" name="bill" id="bill" class="correct">
    </legend>
    
    <legend>
      <label for="custom">select tip %</label>
      <button type="button">5%</button>
      <button type="button" class="">10%</button>
      <button type="button">15%</button>
      <button type="button">25%</button>
      <button type="button">50%</button>
      <input placeholder="custom" name="custom" id="custom" class="">
    </legend>
    
    <legend>
      <label for="people">Number of People</label>
      <p class="warning" style="display: inline;">Can't be zero</p>
      <input type="number" name="people" id="people" class="">
    </legend>
  </div>
  
  <div class="output">
    <div>
      <div>
        <div>
          <span>tip amount</span>
          <span>/ person</span>
        </div>
        
        <span class="tip-person" data-tip-person=""></span>
      </div>
      
      <div>
        <div>
          <span>Total</span>
          <span>/ person</span>
        </div>
        
        <span class="total-person" data-total-person=""></span>
      </div>
    </div>
    
    <button type="submit" style="display: block;">Calculate</button>
    <button type="reset" class="" style="display: none;">Reset</button>
  </div>
</form>
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement