Skip to main content

How to Float Form Labels

Headshot of Michael Spellacy (Spell)
  • Posted by: Michael Spellacy (Spell), Director, Accessibility
  • Pronouns: He/Him
  • Posted: Friday, June 18, 2021
  • Update: Tuesday, August 20, 2024

Anti-Pattern: This is considered an anti-pattern. Including a visible and static label, often outside of the field, is always the best solution. Please understand the risks associated with this technique before using.

Since it comes up often, the following is a quick example of how to float form labels. For career site purposes, you will likely wish to use Example 3. Eventually, we will get this into the componet library.

Example 1: Inner Float (CSS Only) Anchor ()

HTML

<form class="search-form inner-float">

  <div class="search-form-container">

    <div class="search-form-item">
  
      <input id="item-1" required>
  
      <label for="item-1">Enter a Keyword</label>
  
    </div>
  
    <div class="search-form-item">
  
      <input id="item-2" required>
  
      <label for="item-2">City, State</label>
  
    </div>
  
    <div class="search-form-item">
  
      <select id="item-3" required>
        <option></option>
        <option>10 Miles</option>
        <option>75 Miles</option>
        <option>500 Miles</option>
      </select>
  
      <label for="item-3">Radius</label>
  
    </div>
  
    <div class="search-form-item">
  
      <input type="submit" value="Submit">
  
    </div>

  </div>
  
</form>

Example 2: Outer Float (CSS Only) Anchor ()

HTML

<form class="search-form outer-float">

  <div class="search-form-container">

    <div class="search-form-item">
  
      <input id="item-4" required>
  
      <label for="item-4">Enter a Keyword</label>
  
    </div>
  
    <div class="search-form-item">
  
      <input id="item-5" required>
  
      <label for="item-5">City, State</label>
  
    </div>
  
    <div class="search-form-item">
  
      <select id="item-6" required>
        <option></option>
        <option>10 Miles</option>
        <option>75 Miles</option>
        <option>500 Miles</option>
      </select>
  
      <label for="item-6">Radius</label>
  
    </div>
  
    <div class="search-form-item">
  
      <input type="submit" value="Submit">
  
    </div>

  </div>
  
</form>

Example 3: Outer Float (CSS and JavaScript) Anchor ()

Note: Use in circumstances when fields are dynamic in nature or include pre-populated fields on page load.

HTML

<form class="search-form outer-float-js">

  <div class="search-form-container">

    <div class="search-form-item">
  
      <input id="item-7" required>
  
      <label for="item-7">Enter a Keyword</label>
  
    </div>
  
    <div class="search-form-item">
  
      <input class="search-location has-text" id="item-8" required value="Allentown, PA">
  
      <label for="item-8">Country, City, State or Zip Code</label>
  
    </div>
  
    <div class="search-form-item">
  
      <select id="item-9" required disabled>
        <option value>Please Select</option>
        <option value="10">10 Miles</option>
        <option value="75">75 Miles</option>
        <option value="500">500 Miles</option>
      </select>
  
      <label for="item-9">Radius</label>
  
    </div>
  
    <div class="search-form-item">
  
      <input type="submit" value="Submit">
  
    </div>

  </div>
  
</form>

CSS (All Examples)

/*!

  Floating Labels Example

  Contributor(s):
  Michael "Spell" Spellacy

  sass --watch init.scss:../../media/2021-06-18-floating-labels/init.css --style compressed

*/

// Example 1: Inner Float

.inner-float {

  .search-form-container {

    @media (min-width: 64em) {

      display: grid;
      gap: 0.625em;
      grid-template-columns: repeat(4, 1fr);

    }

    .search-form-item {
    border: 1px #6F00EF solid;
    margin: 1em 0;
    position: relative;
    }

    label {
    display: block;
    font-size: 16px;
    inset-block-start: 50%;
    inset-inline-start: 20px;
    line-height: normal;
    margin: 0;
    position: absolute;
    transform: translateY(-50%);
    transition: all .2s ease;
    z-index: 1;
    }

    input, select {
    border: 0;
    font-size: 1.25rem;
    height: 100%;
    width: 100%;
  
      &:not([type="submit"]) {
      background-color: transparent;
      display: block;
      margin: 0;
      padding: 30px 20px 10px;
      position: relative;
    
        &:focus ~ label, &:valid ~ label {
        font-size: 13px;
        inset-block-start: 14px;
        }

        &:focus {
        background-color: lightgoldenrodyellow;
        }

      }

      &[type="submit"] {
      background-color: #6F00EF;
      color: #fff;
      padding: 1em;
      }

    }

  }

}

// Example 2: Outer Float

.outer-float {

  .search-form-container {

    @media (min-width: 64em) {

      display: grid;
      gap: 0.625em;
      grid-template-columns: repeat(4, 1fr);

    }

    .search-form-item {
    border: 1px #6F00EF solid;
    margin: 40px 0;
    position: relative;
    }

    label {
    display: block;
    font-size: 16px;
    inset-block-start: 50%;
    inset-inline-start: 20px;
    line-height: normal;
    margin: 0;
    position: absolute;
    transform: translateY(-50%);
    transition: all .2s ease;
    z-index: 1;
    }

    input, select {
    border: 0;
    font-size: 1.25rem;
    height: 100%;
    width: 100%;
  
      &:not([type="submit"]) {
      background-color: transparent;
      display: block;
      margin: 0;
      padding: 20px;
      position: relative;
    
        &:focus ~ label, &:valid ~ label {
        font-size: 13px;
        inset-block-start: -18px;
        }

        &:focus {
        background-color: lightgoldenrodyellow;
        }

      }

      &[type="submit"] {
      background-color: #6F00EF;
      color: #fff;
      padding: 1em;
      }

    }

  }

}

// Example 3: Outer Float (JS)

.outer-float-js {
  
  .search-form-container {
  
    @media (min-width: 64em) {
  
      display: grid;
      gap: 0.625em;
      grid-template-columns: repeat(4, 1fr);
  
    }
  
    .search-form-item {
    border: 1px #6F00EF solid;
    margin: 40px 0;
    position: relative;

      &:has([disabled]) {
      border-color: #808080;
      }

      &:has([disabled] ~ label) {
      color: #808080;
      }

    }
  
    label {
    display: block;
    font-size: 16px;
    inset-block-start: 50%;
    inset-inline-start: 20px;
    line-height: normal;
    margin: 0;
    position: absolute;
    transform: translateY(-50%);
    transition: all .2s ease;
    z-index: 1;
    }
  
    input, select {
    border: 0;
    font-size: 1.25rem;
    height: 100%;
    width: 100%;
    
      &:not([type="submit"]), select {
      background-color: transparent;
      display: block;
      margin: 0;
      padding: 20px;
      position: relative;

        &.has-text, &.has-focus {
        color: inherit;
  
          ~ label {
            font-size: 13px;
            inset-block-start: -18px;
  
          }
  
        }

        &.has-focus {
        background-color: lightgoldenrodyellow;
        }
      
      }
  
      &[type="submit"] {
      background-color: #6F00EF;
      color: #fff;
      padding: 1em;
      }
  
    }

    select {
    color: transparent; // HACK: This is so that the select text does not show up _behind_ the label. Hacky hack is hacky. Wondering if SEO red flag?

      &[disabled], &[disabled] ~ label {
      cursor: not-allowed;
      }

    }
  
  }
  
}

JavaScript

/*!

  Floating Labels Example: Outer Float (JS)

  Contributor(s):
  Michael "Spell" Spellacy

*/

var searchFormField = document.querySelectorAll(".outer-float-js input:not([type=submit]), .outer-float-js select");
var locationField = document.querySelectorAll(".search-location");

searchFormField.forEach(function(field){

  field.addEventListener("focus", function(){

    field.classList.add("has-focus");

  });

  field.addEventListener("blur", function(){

    field.classList.remove("has-focus");

    if (field.value !== "") {

       field.classList.add("has-text");

    } else {

      field.classList.remove("has-text");

    }

  });

});

locationField.forEach(function(field){

  field.addEventListener("blur", function(){

    var radiusField = field.parentNode.nextElementSibling.querySelector("select");

    if(field.value !== "") {

      radiusField.classList.add("has-text")
      radiusField.removeAttribute("disabled");

    } else {

      radiusField.classList.remove("has-text");
      radiusField.setAttribute("disabled", "");

    }

  });

});

function checkSearchFormFields() {

  locationField.forEach(function(field){

    var radiusField = field.parentNode.nextElementSibling.querySelector("select");

    if (field.value !== "") {

      field.classList.add("has-text");

      radiusField.classList.add("has-text");
      radiusField.removeAttribute("disabled");

    }

  });

}

checkSearchFormFields();