On remove "required" label not working properly

243 Views Asked by At

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

3

There are 3 best solutions below

14
yherbawi On BEST ANSWER

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>

1
Laaouatni Anas On

I changed from this

.select-text:focus~.select-label,
.select-text:valid~.select-label {

/* your code */

}

to this

.select-text:focus~.select-label {
    
/* your code */

}

now is working, here the fixed code:

.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, where I changed */

.select-text:focus~.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;
}
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
</head>

<body>
  <div class="wrap">
    <!--Select with pure css-->
    <div class="select">
      <select class="select-text">
        <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>

0
Nitheesh On

Its working as expected.

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

This is happening because of this style .select-text:valid ~ .select-label

When the select is required, if you select the first option whose value is null, then your select is invaid and the css style .select-text:valid ~ .select-label wont work whch means your label will be in grey colour. If the select is not required, then if you select first option, then the .select-text will be in valid state, and the style .select-text:valid ~ .select-label will be applied, which makes the label small and blue.

To fix this, we have to use a css + javascript solution.

I have implemented the solution by refering this answer.

Working Solution

.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 ======================================= */


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

.select-label,
.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;
}



/* 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;
}
<div class="wrap">

<!--Select with pure css-->
  <div class="select">
      <select class="select-text" onchange="this.dataset.chosen = this.value; ">
        <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">Please Select</label>
    </div>
<!--Select with pure css-->

</div>