0

What I am trying to do is change the label font color and border color when the input field is focused. Is there a way to make that happen without using JavaScript?

.input-label {
    display: flex;
    align-items: center;
    height: 16px;
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .1px;
    color: #989898;
    text-transform: uppercase;
}
.form-control{
    display: inline-block;
    max-width: 100%;
    word-wrap: normal;
    background: transparent;
    border: none;
    border-bottom: 2px solid #cacaca;
    color: #4a4a4a;
    font-size: 1.19em;
    height: 35px;
    letter-spacing: .2px;
    padding: 7px 0;
    width: 100%;
    resize: none;
}
input:focus{
  /* after the input is focused the labele font color and border color change to something else*/
}
<div class="firstname">
<label for="name" class="input-label" id="name-label">First Name</label>
<input type="text" class="form-control" id="name" placeholder="First Name" required>
</div>
TylerH
  • 20,799
  • 66
  • 75
  • 101

3 Answers3

2

CSS does not have selectors to climb up the DOM tree, to use CSS to modify style of an element from another one being focused, it has to stand ahead as a sibling or a parent.

But it has flex or grid with order that allows to reorder elements at screen, so you can rewrite your HTML and set the label right behind the input and still show it , print it ahead that input.

Here is an example with grid (builds a grid of 1 single column if not set otherwise) and order.

.firstname {
  display: grid;
}

.input-label {
  display: flex;
  align-items: center;
  height: 16px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .1px;
  color: #989898;
  text-transform: uppercase;
  order: -1;
}

.form-control {
  display: inline-block;
  max-width: 100%;
  word-wrap: normal;
  background: transparent;
  border: none;
  border-bottom: 2px solid #cacaca;
  color: #4a4a4a;
  font-size: 1.19em;
  height: 35px;
  letter-spacing: .2px;
  padding: 7px 0;
  width: 100%;
  resize: none;
}

input:focus+label {
  color: red;
}
<div class="firstname">
  <input type="text" class="form-control" id="name" placeholder="First Name" required>
  <label for="name" class="input-label" id="name-label">First Name</label>
</div>

https://developer.mozilla.org/en-US/docs/Web/CSS/order

The order CSS property sets the order to lay out an item in a flex or grid container. Items in a container are sorted by ascending order value and then by their source code order.

If you have a single duo of input/label within the form, then within-focus is the easiest option.

G-Cyrillus
  • 101,410
  • 14
  • 105
  • 129
2

You can use the :focus-within pseudo-class:

matches an element if the element or any of its descendants are focused.

You might want to check if the browser compatibility fits your requirements at caniuse.com

And create a selector like this:

    .firstname:focus-within .input-label {
      color: red;
    }

.input-label {
  display: flex;
  align-items: center;
  height: 16px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .1px;
  color: #989898;
  text-transform: uppercase;
}

.form-control {
  display: inline-block;
  max-width: 100%;
  word-wrap: normal;
  background: transparent;
  border: none;
  border-bottom: 2px solid #cacaca;
  color: #4a4a4a;
  font-size: 1.19em;
  height: 35px;
  letter-spacing: .2px;
  padding: 7px 0;
  width: 100%;
  resize: none;
}

.firstname:focus-within .input-label {
  color: red;
}
<div class="firstname">
  <label for="name" class="input-label" id="name-label">First Name</label>
  <input type="text" class="form-control" id="name" placeholder="First Name" required>
</div>

Alternatively, you could place your label after the input and reorder them using CSS.

t.niese
  • 39,256
  • 9
  • 74
  • 101
0

So in html, just let the label empty and put input first and label in second.

Then here is the CSS. The goal is to use css selector + to put label back as first position.

Then you change the label css how you wish :

/* CSS ADDED */
.firstname{
  display:flex;
}
.firstname > *:last-child {
  order:-1;
}

input:focus + label{
  color: red;
  border: 3px solid red;
  padding: 5px;
}

DEMO:

.input-label {
    display: flex;
    align-items: center;
    height: 16px;
    font-weight: 700;
    font-size: 11px;
    letter-spacing: .1px;
    color: #989898;
    text-transform: uppercase;
}
.form-control{
    display: inline-block;
    max-width: 100%;
    word-wrap: normal;
    background: transparent;
    border: none;
    border-bottom: 2px solid #cacaca;
    color: #4a4a4a;
    font-size: 1.19em;
    height: 35px;
    letter-spacing: .2px;
    padding: 7px 0;
    width: 100%;
    resize: none;
}
/* CSS ADDED */
.firstname{
  display:flex;
  flex-direction: column;
}
.firstname > *:last-child {
  order:-1;
}

input:focus + label{
  color: red;
  border: 3px solid red;
  padding: 5px;
}
<div class="firstname">
  <input type="text" class="form-control" id="name" placeholder="First Name" required>
  <label for="name" class="input-label" id="name-label">First Name</label>
</div>
MaxiGui
  • 6,190
  • 4
  • 16
  • 33
  • The purpose of a `label` is that it carries some information. In your case, you could just remove the `label`. If you suggest your method you should at least show how the label could retain its purpose. The problem with `:before` and `:after` is that they should only be used for decorative purposes. So with accessibility in mind, that will be problematic. – t.niese Sep 09 '21 at 15:28
  • @t.niese I agree, but I read wrong, because I thought he wanted to change the text inside the label, but he just wants to change the *label font color and border color* so I can do it but no need of the `:before` and `:after`. Look now what I did – MaxiGui Sep 09 '21 at 15:33