Search code examples
javascripthtmlcssmaterial-designpure-css

On remove "required" label not working properly


Codepen: link


.body {
  position: relative;
  font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
}

.wrap {
  position: absolute;
  right: 0;
  top: 40%;
  width: 350px;
  left: 0;
  margin: 0 auto;
}


/* select starting stylings ------------------------------*/

.select {
  font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
  position: relative;
  width: 350px;
}

.select-text {
  position: relative;
  font-family: inherit;
  background-color: transparent;
  width: 350px;
  padding: 10px 10px 10px 0;
  font-size: 18px;
  border-radius: 0;
  border: none;
  border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}


/* Remove focus */

.select-text:focus {
  outline: none;
  border-bottom: 1px solid rgba(0, 0, 0, 0);
}


/* Use custom arrow */

.select .select-text {
  appearance: none;
  -webkit-appearance: none
}

.select:after {
  position: absolute;
  top: 18px;
  right: 10px;
  /* Styling the down arrow */
  width: 0;
  height: 0;
  padding: 0;
  content: '';
  border-left: 6px solid transparent;
  border-right: 6px solid transparent;
  border-top: 6px solid rgba(0, 0, 0, 0.12);
  pointer-events: none;
}


/* LABEL ======================================= */

.select-label {
  color: rgba(0, 0, 0, 0.26);
  font-size: 18px;
  font-weight: normal;
  position: absolute;
  pointer-events: none;
  left: 0;
  top: 10px;
  transition: 0.2s ease all;
}


/* active state */

.select-text:focus~.select-label,
.select-text:valid~.select-label {
  color: #2F80ED;
  top: -20px;
  transition: 0.2s ease all;
  font-size: 14px;
}


/* BOTTOM BARS ================================= */

.select-bar {
  position: relative;
  display: block;
  width: 350px;
}

.select-bar:before,
.select-bar:after {
  content: '';
  height: 2px;
  width: 0;
  bottom: 1px;
  position: absolute;
  background: #2F80ED;
  transition: 0.2s ease all;
}

.select-bar:before {
  left: 50%;
}

.select-bar:after {
  right: 50%;
}


/* active state */

.select-text:focus~.select-bar:before,
.select-text:focus~.select-bar:after {
  width: 50%;
}


/* HIGHLIGHTER ================================== */

.select-highlight {
  position: absolute;
  height: 60%;
  width: 100px;
  top: 25%;
  left: 0;
  pointer-events: none;
  opacity: 0.5;
}
<html>
<head>
</head>
<body>
  <div class="wrap">
    <!--Select with pure css-->
    <div class="select">
      <select class="select-text" required>
        <option value="" disabled selected></option>
        <option value="1">Option 1</option>
        <option value="2">Option 2</option>
        <option value="3">Option 3</option>
      </select>
      <span class="select-highlight"></span>
      <span class="select-bar"></span>
      <label class="select-label">Select</label>
    </div>
    <!--Select with pure css-->

  </div>
</body>

</html>

When the <select> is required, then it's working fine.

But The problem is that when I removed "required", it's Label Floating without the selected option.

How can I maintain the floating label in this case?
I'm missing anything? Or do we need JavaScript?

So the idea is not to float the label when it is empty.

I resolved the input issue using link


Solution

  • Simply remove :valid selector, valid is always true if the input in not required.

    so after removing this:

    .select-text:valid ~ .select-label
    

    You'll face another problem which is keeping the label up after :focus is removed if the user selects an option.

    so you'll need to add onchange event

    onchange="this.dataset.chosen=this.value;"
    

    Then you can easily make the label stay if the user has selected an option.

    .select-text[data-chosen] ~.select-label
    

    This way the label stays up if the select has a value.

    it becomes like the following snippet:

    .body {
      position: relative;
      font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
    }
    
    .wrap {
      position: absolute;
      right: 0;
      top: 40%;
      width: 350px;
      left: 0;
      margin: 0 auto;
    }
    
    
    /* select starting stylings ------------------------------*/
    
    .select {
      font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
      position: relative;
      width: 350px;
    }
    
    .select-text {
      position: relative;
      font-family: inherit;
      background-color: transparent;
      width: 350px;
      padding: 10px 10px 10px 0;
      font-size: 18px;
      border-radius: 0;
      border: none;
      border-bottom: 1px solid rgba(0, 0, 0, 0.12);
    }
    
    
    /* Remove focus */
    
    .select-text:focus {
      outline: none;
      border-bottom: 1px solid rgba(0, 0, 0, 0);
    }
    
    
    /* Use custom arrow */
    
    .select .select-text {
      appearance: none;
      -webkit-appearance: none
    }
    
    .select:after {
      position: absolute;
      top: 18px;
      right: 10px;
      /* Styling the down arrow */
      width: 0;
      height: 0;
      padding: 0;
      content: '';
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      border-top: 6px solid rgba(0, 0, 0, 0.12);
      pointer-events: none;
    }
    
    
    /* LABEL ======================================= */
    
    .select-label {
      color: rgba(0, 0, 0, 0.26);
      font-size: 18px;
      font-weight: normal;
      position: absolute;
      pointer-events: none;
      left: 0;
      top: 10px;
      transition: 0.2s ease all;
    }
    
    
    /* active state */
    
    .select-text:focus~.select-label,
    .select-text[data-chosen] ~.select-label{
      color: #2F80ED;
      top: -20px;
      transition: 0.2s ease all;
      font-size: 14px;
    }
    
    
    /* BOTTOM BARS ================================= */
    
    .select-bar {
      position: relative;
      display: block;
      width: 350px;
    }
    
    .select-bar:before,
    .select-bar:after {
      content: '';
      height: 2px;
      width: 0;
      bottom: 1px;
      position: absolute;
      background: #2F80ED;
      transition: 0.2s ease all;
    }
    
    .select-bar:before {
      left: 50%;
    }
    
    .select-bar:after {
      right: 50%;
    }
    
    
    /* active state */
    
    .select-text:focus~.select-bar:before,
    .select-text:focus~.select-bar:after {
      width: 50%;
    }
    
    
    /* HIGHLIGHTER ================================== */
    
    .select-highlight {
      position: absolute;
      height: 60%;
      width: 100px;
      top: 25%;
      left: 0;
      pointer-events: none;
      opacity: 0.5;
    }
    <html>
    <head>
    </head>
    <body>
      <div class="wrap">
        <!--Select with pure css-->
        <div class="select">
          <select class="select-text" onchange="this.dataset.chosen=this.value;">
            <option value="" disabled selected></option>
            <option value="1">Option 1</option>
            <option value="2">Option 2</option>
            <option value="3">Option 3</option>
          </select>
          <span class="select-highlight"></span>
          <span class="select-bar"></span>
          <label class="select-label">Select</label>
        </div>
        <!--Select with pure css-->
    
      </div>
    </body>
    
    </html>

    EDIT:

    This new solution works if the user selects empty option, the label come down,

    I simply added the empty value selector to keep the label up, and added a blur() event when the select change to smooth everything.

    Check out the snippet:

    .body {
      position: relative;
      font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
    }
    
    .wrap {
      position: absolute;
      right: 0;
      top: 40%;
      width: 350px;
      left: 0;
      margin: 0 auto;
    }
    
    
    /* select starting stylings ------------------------------*/
    
    .select {
      font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif;
      position: relative;
      width: 350px;
    }
    
    .select-text {
      position: relative;
      font-family: inherit;
      background-color: transparent;
      width: 350px;
      padding: 10px 10px 10px 0;
      font-size: 18px;
      border-radius: 0;
      border: none;
      border-bottom: 1px solid rgba(0, 0, 0, 0.12);
    }
    
    
    /* Remove focus */
    
    .select-text:focus {
      outline: none;
      border-bottom: 1px solid rgba(0, 0, 0, 0);
    }
    
    
    /* Use custom arrow */
    
    .select .select-text {
      appearance: none;
      -webkit-appearance: none
    }
    
    .select:after {
      position: absolute;
      top: 18px;
      right: 10px;
      /* Styling the down arrow */
      width: 0;
      height: 0;
      padding: 0;
      content: '';
      border-left: 6px solid transparent;
      border-right: 6px solid transparent;
      border-top: 6px solid rgba(0, 0, 0, 0.12);
      pointer-events: none;
    }
    
    
    /* LABEL ======================================= */
    
    .select-label,select.select-text[data-chosen=""] ~.select-label {
      color: rgba(0, 0, 0, 0.26);
      font-size: 18px;
      font-weight: normal;
      position: absolute;
      pointer-events: none;
      left: 0;
      top: 10px;
      transition: 0.2s ease all;
    }
    
    
    /* active state */
    
    select.select-text:focus~.select-label,
    .select-text[data-chosen] ~.select-label{
      color: #2F80ED;
      top: -20px;
      transition: 0.2s ease all;
      font-size: 14px;
    }
    
    
    /* BOTTOM BARS ================================= */
    
    .select-bar {
      position: relative;
      display: block;
      width: 350px;
    }
    
    .select-bar:before,
    .select-bar:after {
      content: '';
      height: 2px;
      width: 0;
      bottom: 1px;
      position: absolute;
      background: #2F80ED;
      transition: 0.2s ease all;
    }
    
    .select-bar:before {
      left: 50%;
    }
    
    .select-bar:after {
      right: 50%;
    }
    
    
    /* active state */
    
    .select-text:focus~.select-bar:before,
    .select-text:focus~.select-bar:after {
      width: 50%;
    }
    
    
    /* HIGHLIGHTER ================================== */
    
    .select-highlight {
      position: absolute;
      height: 60%;
      width: 100px;
      top: 25%;
      left: 0;
      pointer-events: none;
      opacity: 0.5;
    }
    <html>
    <head>
    </head>
    <body>
      <div class="wrap">
        <!--Select with pure css-->
        <div class="select">
          <select class="select-text" onchange="this.dataset.chosen=this.value;this.blur();">
            <option value="" selected></option>
            <option value="1">Option 1</option>
            <option value="2">Option 2</option>
            <option value="3">Option 3</option>
          </select>
          <span class="select-highlight"></span>
          <span class="select-bar"></span>
          <label class="select-label">Select</label>
        </div>
        <!--Select with pure css-->
    
      </div>
    </body>
    
    </html>