1

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

Sid Sss
  • 129
  • 2
  • 13

3 Answers3

3

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>
yherbawi
  • 509
  • 2
  • 7
  • As I mentioned this is not a mandatory field, so once the user select he has to choose any one of the options. If he selects a blank option then the label should come down. – Sid Sss Jan 04 '22 at 11:39
  • If I removed the disabled selected from the first option, it won't work. It should not float. – Sid Sss Jan 04 '22 at 11:41
  • 1
    @SidSss I updated the answer, now if the user selects empty option the label comes down. – yherbawi Jan 04 '22 at 12:50
  • On dynamic data, the label comes down even if the – Sid Sss Jan 11 '22 at 11:01
  • On reload page, the label comes down even if the Solution Please. – Sid Sss Jan 11 '22 at 12:12
  • 1
    Simply add `data-chosen="Value"` when you send your dynamic data. set the value same as the dynamic value chosen. – yherbawi Jan 11 '22 at 13:07
  • I have apply $('#selectId').attr("data-chosen", "" + $("#selectId option:selected").val() + ""); as per ID. how do I apply for multiple Id's?Any common solution for this? – Sid Sss Feb 10 '22 at 08:21
  • what do you mean by multiple id's? if you want to select an array of elements you can simply use `document.querySelectorAll('here put your selector')` and using a loop like `.forEach` method or any other way. but the selector must by a class or so but not an id, because id must by unique. if you want to do so multiple diffrent id's you could use a loop. – yherbawi Feb 11 '22 at 09:08
  • how can we achieve it by using only class? – Sid Sss Feb 11 '22 at 09:11
  • could you elaborate exactly what are you trying to do – yherbawi Feb 11 '22 at 09:20
  • imagine there are 2 forms. In 1st form, there is a table view, on click edit action I'm redirected to 2nd form (i.e add new form) with all details saved by the user. when the form is reloaded with that dynamic data the select option label is overlapping. so for this, I had written a script `$('#selectId').attr("data-chosen", "" + $("#selectId option:selected").val() + "");` . and it's working fine. but as there are multiple selections, I don't want to write code for every select field. So how can we modify the script and able to solve this kind of issue? – Sid Sss Feb 11 '22 at 11:00
  • First it's a mistake to have multiple elements with the same id, you should give those selects a class, and you can use this `document.querySelectorAll('.myselectclass').forEach(elm=>{ elm.setAttribute('data-chosen',elm.querySelector('option:selected').value); })` this is pure js you can use it as it is or change it to jquery. – yherbawi Feb 11 '22 at 12:00
  • getting error : Failed to execute 'querySelector' on 'Element': 'option:selected' is not a valid selector. – Sid Sss Feb 12 '22 at 05:53
  • You should post your code in a new question. – yherbawi Feb 13 '22 at 20:46
1

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>
Laaouatni Anas
  • 4,199
  • 2
  • 7
  • 26
0

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>
Nitheesh
  • 19,238
  • 3
  • 22
  • 49