Add a remove button ✖ on an input

One simple feature I had to code for work was adding a remove cross button at the end of an input to be able to clear the input faster. I thought it would be very easy to code, but as always I encountered a lot of surprises before being able to implement the feature successfully.

The feature is simple: on a form input we want to add a reset button that will look like a cross on the right side of the input.

  • Reset button visible only when a first character is entered in the input field
  • When click on the reset button the characters in the input to disappear
  • Reset button hidden after clearing the input as there are no characters left to clear

I simplified the code to show you an example of an implementation using HTML, SCSS and Javascript. Here is how the feature will look like :

I found two different ways of implementing this feature.

First option – CSS display property

The first one using the CSS property display on the class of the button (display none and display block) watching the behavior of the input, using JavaScript.

First, we begin with the static code. HTML and SCSS.

The HTML is really basic: a have a general div, with two children: input and button. I decided to add the selectors input-text on the input, and search-reset on the button to be able to query them in the JavaScript part. You could also use ids instead. For the button I used an element em with the icon ✖, here you can replace the icon with the one you want.

<div class="search">
  <input class="search__text-input" input-text>
  <button class="search__delete-button" type="button" search-reset>
      <em class="search__delete-button__icon">✖</em>
  </button>
</div>

I am using SCSS instead of plane CSS because I like to use the BEM class naming convention. I found it easier to read and cleaner. If you want to learn more about BEM here is a link to an article about it on one of my favorite resources: CSS-Trick !

I also kept the SCSS very simple, so you can customize it the way you want. The most important here is that the div .search has a position relative, so we are able to set a position absolute on the button.

.search {
  position: relative;
  width: 200px;
  
  &__text-input {
    height: 30px;
    width: 200px;
    outline: none;
    padding-left: 5px;
  }
  
  &__delete-button {
    position: absolute;
    top: 6px;
    right: 5px;
    align-items: center;
    justify-content: center;
    border: 0;
    background: none;
    padding: 0;
    cursor: pointer;
    color: black;
    font-size: 22px;
    user-select: none;

    &:hover,
    &:active {
        color: grey;
    }
  
    &__icon {
      font-weight: 400;
      font-style: normal;
    }
  }
}

For the JavaScript, I am initializing two event listeners.

  • keyup, that means every time the user press a key on the keyboard, the function displayResetButton() will be called
  • click on the reset button will run the function handleReset()
⚠ Note!
I started by using the event keydown, but it didn't work because the event was happening before the character was being recorded in the input variable. That is why, in this case, make sure to use the event keyup that happens when the key goes up.

The function displayResetButton() will check if the input contains characters, if yes then it will display the button, otherwise, it will hide it.

The function handleReset() will clear the input field and hide the reset button.

this.buttonReset = document.querySelector('[search-reset]');
this.inputQuery = document.querySelector('[input-text]');
this.displayResetButton();
this.bindEvents();

function bindEvents() {
  this.inputQuery.addEventListener('keyup', this.displayResetButton.bind(this));
  this.buttonReset.addEventListener('click', this.handleReset.bind(this));
}

function displayResetButton() {
  if (this.inputQuery.value.length > 0) {
    this.buttonReset.style.display = 'block';
  } else {
    this.buttonReset.style.display = 'none';
  }
}

function handleReset(event) {
  event.preventDefault();

  if (this.inputQuery) {
    this.inputQuery.value = '';
    this.buttonReset.style.display = 'none';
  }
}

Second option – add/remove class

The second one would be to add a CSS class “active”, and “inactive”, each class would contain the CSS code corresponding to its state. The JavaScript will only add the right class and remove the wrong one, watching the behavior of the input.

The HTML code is the same as the first option, I am just adding the .inactive class on the button, so the cross won’t be visible at first.

<div class="search">
  <input class="search__text-input" input-text>
  <button id="test" class="search__delete-button inactive" type="button" search-reset>
      <em class="search__delete-button__icon">✖</em>
  </button>
</div>

The difference is that I isolated the code of the displayed button under the class .active, and only apply a display none when the .inactive class is enabled.

.search {
  position: relative;
  width: 200px;
  
  &__text-input {
    height: 30px;
    width: 200px;
    outline: none;
    padding-left: 5px;
  }
  
  &__delete-button {
    &.active {
      display: block;
      position: absolute;
      top: 6px;
      right: 5px;
      align-items: center;
      justify-content: center;
      border: 0;
      background: none;
      padding: 0;
      cursor: pointer;
      color: black;
      font-size: 22px;
      user-select: none;

      &:hover,
      &:active {
          color: grey;
      }
    }
    
    &.inactive {
      display: none;
    }
    
    &__icon {
      font-weight: 400;
      font-style: normal;
    }
  }
}

I added two functions: activateButton() and desactivateButton() handling the addition of the right class and the suppression of the wrong one.

this.buttonReset = document.querySelector('[search-reset]');
this.inputQuery = document.querySelector('[input-text]');
this.displayResetButton();
this.bindEvents();

function bindEvents() {
  this.inputQuery.addEventListener('keyup', this.displayResetButton.bind(this));
  this.buttonReset.addEventListener('click', this.handleReset.bind(this));
}

function displayResetButton() {
  if (this.inputQuery.value.length > 0) {
    this.activateButton();
  } else {
    this.desactivateButton();
  }
}

function handleReset(event) {
  event.preventDefault();

  if (this.inputQuery) {
    this.inputQuery.value = '';
    this.desactivateButton();
  }
}

function activateButton() {
  this.buttonReset.classList.add('active');
  this.buttonReset.classList.remove('inactive');
}

function desactivateButton() {
  this.buttonReset.classList.add('inactive');
  this.buttonReset.classList.remove('active');
}
TheTrendyBrand