201

How do I apply a style to an empty input box? If the user types something in the input field, the style should no longer be applied. Is this possible in CSS? I tried this:

input[value=""]
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Sjoerd
  • 74,049
  • 16
  • 131
  • 175

15 Answers15

246

In modern browsers you can use :placeholder-shown to target the empty input (not to be confused with ::placeholder).

input:placeholder-shown {
    border: 1px solid red; /* Red border only if the input is empty */
}

In HTML you must set the placeholder attribute. Chrome browser requires at least a space character as value.

<input type="text" placeholder=" "> <!-- Do not remove placeholder -->
Dan Froberg
  • 168
  • 8
Berend
  • 2,889
  • 1
  • 18
  • 13
  • 5
    @TricksfortheWeb It does seem to require a placeholder attribute (with a value) to be present in the input tag. Tested in Chrome - not sure if this counts for all browsers. – Berend Mar 17 '17 at 06:23
  • 23
    Placeholder attribute have to be set. Anyway we can set placeholder attribute as whitespace. – Piotr Kozłowski May 30 '17 at 10:07
  • 1
    Example of it in production use https://codepen.io/fossprime/pen/BdWeNr?editors=1100 I used this in production while having graceful degradability... it looks and feels better if supported, but isn't a usability issue if it's not. – Ray Foss Aug 08 '17 at 20:48
  • @TricksfortheWeb It only seems to work if there is a non-empty placeholer https://codepen.io/ryanve/pen/XejOzG – ryanve Sep 22 '17 at 22:38
  • 2
    @Amanpreet According to https://caniuse.com/#search=placeholder, this won't work in IE 11 either (or Edge). – Tim Malone Oct 19 '17 at 02:07
  • 4
    Not supported in Microsoft browsers at all: https://caniuse.com/#feat=css-placeholder-shown – Lounge9 Dec 11 '17 at 21:19
  • `:-ms-input-placeholder` seems to work in IE11 as long as the placeholder isn't an empty string, i.e. `placeholder=" "` (a single space) works OK for me. – DigitalDan Nov 15 '18 at 13:37
  • It's supported in Edge v79 onward (since Edge v79 onward is Chromium-based). – T.J. Crowder May 27 '20 at 09:36
  • it doesn't work for me! Tested it in Safari, Chrome and Firefox but it's doing nothing. – trueToastedCode Apr 06 '23 at 09:13
  • 1
    It's now supported in edge since v79. @trueToastedCode you have to set the placeholder-attribute like placeholder=" " - empty string does not work (tested in Chrome). – Simon Apr 12 '23 at 11:08
178

If only the field is required you could go with input:valid

#foo-thing:valid + .msg { visibility: visible!important; }      
 <input type="text" id="foo-thing" required="required">
 <span class="msg" style="visibility: hidden;">Yay not empty</span>

See live on jsFiddle

OR negate using #foo-thing:invalid (credit to @SamGoody)

Utkarsh Dubey
  • 703
  • 11
  • 31
lukmdo
  • 7,489
  • 5
  • 30
  • 23
  • 17
    ..or negate by using :invalid{} https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid?redirectlocale=en-US&redirectslug=CSS%2F%3Ainvalid – SamGoody Jan 30 '14 at 08:18
  • 7
    I want same thing, but my field is not required. is there any way to do so? – Zahidul Islam Ruhel Nov 09 '17 at 15:13
  • @ZahidulIslamRuhel of course, this answer should not be the top one. see the answer below https://stackoverflow.com/a/35593489/11293716 – jg6 May 30 '20 at 18:38
28

input[value=""], input:not([value])

works with:

<input type="text" />
<input type="text" value="" />

But the style will not change as soon as someone will start typing (you need JS for that).

T.Todua
  • 53,146
  • 19
  • 236
  • 237
Draco Ater
  • 20,820
  • 8
  • 62
  • 86
  • 3
    Not reliable as the value attribute is not changed in DOM after a field edit. However, nice trick if you don't care about this - and works in latest Safari, Chrome, FF and IE... – Dunc Nov 12 '13 at 11:00
  • 13
    To match the former, you can use `input[value=""], input:not([value])`. – Schism Jul 10 '14 at 19:53
23

Updating the value of a field does not update its value attribute in the DOM so that's why your selector is always matching a field, even when it's not actually empty.

Instead use the invalid pseudo-class to achieve what you want, like so:

input:required {
  border: 1px solid green;
}
input:required:invalid {
  border: 1px solid red;
}
<input required type="text" value="">

<input required type="text" value="Value">
Shaggy
  • 6,696
  • 2
  • 25
  • 45
11

If supporting legacy browsers is not needed, you could use a combination of required, valid, and invalid.

The good thing about using this is the valid and invalid pseudo-elements work well with the type attributes of input fields. For example:

input:invalid, textarea:invalid { 
    box-shadow: 0 0 5px #d45252;
    border-color: #b03535
}

input:valid, textarea:valid {
    box-shadow: 0 0 5px #5cd053;
    border-color: #28921f;
}
<input type="email" name="email" placeholder="john_doe@example.com" required />
<input type="url" name="website" placeholder="http://johndoe.com"/>
<input type="text" name="name" placeholder="John Doe" required/>

For reference, JSFiddle here: http://jsfiddle.net/0sf6m46j/

My Stack Overfloweth
  • 4,729
  • 4
  • 25
  • 42
10

I realize this is a very old thread, but things have changed a bit since and it did help me find the right combination of things I needed to get my problem fixed. So I thought I'd share what I did.

The problem was I needed to have the same css applied for an optional input if it was filled, as I had for a filled required. The css used the psuedo class :valid which applied the css on the optional input also when not filled.

This is how I fixed it;

HTML

<input type="text" required="required">
<input type="text" placeholder="">

CSS

input:required:valid {
    ....
}
input:optional::not(:placeholder-shown){
    ....
}
jessica
  • 143
  • 1
  • 8
  • What if I need to use it in multiple input fields with actual content in their respective placeholders? – carloswm85 Jun 04 '21 at 14:30
  • Not entirely sure what you're asking, but if the only difference is that you want to have actual placeholders then just add that text instead of the empty string and it should work the same way (in theory, i haven't tested it) – jessica Jul 05 '21 at 10:04
9

This worked for me:

For the HTML, add the required attribute to the input element

<input class="my-input-element" type="text" placeholder="" required />

For the CSS, use the :invalid selector to target the empty input

input.my-input-element:invalid {

}

Notes:

  • About required from w3Schools.com: "When present, it specifies that an input field must be filled out before submitting the form."
digiwand
  • 1,258
  • 1
  • 12
  • 18
8
$('input#edit-keys-1').blur(function(){
    tmpval = $(this).val();
    if(tmpval == '') {
        $(this).addClass('empty');
        $(this).removeClass('not-empty');
    } else {
        $(this).addClass('not-empty');
        $(this).removeClass('empty');
    }
});

in jQuery. I added a class and styled with css.

.empty { background:none; }
Israel Morales
  • 1,681
  • 1
  • 14
  • 6
7

It worked for me to add a class name to the input and then apply CSS rules to that:

<input type="text" name="product" class="product" />

<style>
input[value=""].product {
    display: none;
}
</style>
DeFeNdog
  • 1,156
  • 1
  • 12
  • 25
5

This question might have been asked some time ago, but as I recently landed on this topic looking for client-side form validation, and as the :placeholder-shown support is getting better, I thought the following might help others.

Using Berend idea of using this CSS4 pseudo-class, I was able to create a form validation only triggered after the user is finished filling it.

Here is ademo and explanation on CodePen: https://codepen.io/johanmouchet/pen/PKNxKQ

Johan M.
  • 51
  • 1
  • 4
4

If you're happy not not supporting IE or pre-Chromium Edge (which might be fine if you are using this for progressive enhancement), you can use :placeholder-shown as Berend has said. Note that for Chrome and Safari you actually need a non-empty placeholder for this to work, though a space works.

*,
 ::after,
 ::before {
  box-sizing: border-box;
}

label.floating-label {
  display: block;
  position: relative;
  height: 2.2em;
  margin-bottom: 1em;
}

label.floating-label input {
  font-size: 1em;
  height: 2.2em;
  padding-top: 0.7em;
  line-height: 1.5;
  color: #495057;
  background-color: #fff;
  background-clip: padding-box;
  border: 1px solid #ced4da;
  border-radius: 0.25rem;
  transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}

label.floating-label input:focus {
  color: #495057;
  background-color: #fff;
  border-color: #80bdff;
  outline: 0;
  box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}

label.floating-label input+span {
  position: absolute;
  top: 0em;
  left: 0;
  display: block;
  width: 100%;
  font-size: 0.66em;
  line-height: 1.5;
  color: #495057;
  border: 1px solid transparent;
  border-radius: 0.25rem;
  transition: font-size 0.1s ease-in-out, top 0.1s ease-in-out;
}

label.floating-label input:placeholder-shown {
  padding-top: 0;
  font-size: 1em;
}

label.floating-label input:placeholder-shown+span {
  top: 0.3em;
  font-size: 1em;
}
<fieldset>
  <legend>
    Floating labels example (no-JS)
  </legend>
  <label class="floating-label">
    <input type="text" placeholder=" ">
    <span>Username</span>
  </label>
  <label class="floating-label">
    <input type="Password" placeholder=" ">
    <span>Password</span>
  </label>
</fieldset>
<p>
  Inspired by Bootstrap's <a href="https://getbootstrap.com/docs/4.0/examples/floating-labels/">floating labels</a>.
</p>
Sora2455
  • 744
  • 7
  • 25
2

So I was playing around earlier with the new :where and :is clauses and conceived of this bit of fun, and after finding this post with the :invalid and :placeholder-shown bits, thought I might share this possibility for future reference

:required:where( input, textarea ):where( :placeholder-shown, :invalid ) {
    border-color: var(--warning);
}

which applies the :root { --warning: orange; } color to any required input or textarea, that is either empty or invalid. And that is just downright sexy

WebDragon
  • 876
  • 6
  • 12
1

While no browser currently (2021-10-01) supports it, there is a proposal for a :blank pseudo-class.

ref: https://developer.mozilla.org/en-US/docs/Web/CSS/:blank. Do note, this is experimental, and no browser supports it as of now.

1

This is how you can make it possible. don't forget to set placeholder=" " and required attr to your inputs. you can change the props as you wish.

body{
    display: flex;
    justify-content: center;
    align-items: center;
}
.input-gp {
    margin-top: 150px;
    position: relative;
    
}
.input-gp input {
    position: relative;
    
}
.input-gp label{
    position: absolute;
    left: 5px;
    bottom: 5px;
    transition: all .4s ease;
}
.input-gp input:placeholder-shown + label{
    left: 10px;
    bottom: 5px;
}
.input-gp input:focus + label,
.input-gp input + label{
    bottom: 30px;
    left: 10px;
}
<body>
 <div class="input-gp ">
<input  type="email" name="" id="email" placeholder=" "       required>
   <label class=" position-absolute" for="email"> Email</label>
  </div>
  
 </body>
Sam
  • 25
  • 8
-1

I'm wondered by answers we have clear attribute to get empty input boxes, take a look at this code

/*empty input*/
input:empty{
    border-color: red;
}
/*input with value*/
input:not(:empty){
    border-color: black;
}

UPDATE

input, select, textarea {
    border-color: @green;
    &:empty {
        border-color: @red;
    }
}

More over for having a great look in the validation

 input, select, textarea {
    &[aria-invalid="true"] {
        border-color: amber !important;
    }

    &[aria-invalid="false"], &.valid {
        border-color: green !important;
    }
}
Nasser Hadjloo
  • 12,312
  • 15
  • 69
  • 100
  • 9
    `:empty` applies only to elements that have no children. Inputs can't have child nodes at all so your input will be always with red border. Also see [this comment](http://stackoverflow.com/questions/3617020/matching-an-empty-input-box-using-css#comment23212939_3617050) – Eugene Apr 27 '15 at 14:58
  • 2
    @NasserHadjloo have you tested this? Changing the `value` doesn't change the number of child nodes. – jcuenod Jul 22 '15 at 20:13
  • @jcuenod what do you mean by number of child nodes? I didn't get your point – Nasser Hadjloo Jul 25 '15 at 06:04
  • 1
    In xml structures, nodes are nested (i.e. ``). You just have `` and as you type what's changing is not a `` node inside `` but a value *attribute*: `` – jcuenod Jul 25 '15 at 21:17
  • @jcuenod Honestly speaking, I don't get your point at all, I suggest you test my proposition and you will see that it will work – Nasser Hadjloo Jul 27 '15 at 06:02
  • Your `aria-invalid="true"` selector will work. However, your `:empty` selector will not: http://jsfiddle.net/5ezdhemb/ (note that it stays red because no child nodes are created when the value changes) – jcuenod Jul 27 '15 at 11:16
  • @jcuenod yes You are right, but still when you are validating the form, before submitting, you will see the border-color change – Nasser Hadjloo Jul 28 '15 at 12:59
  • 2
    But that's not what the OP is trying to achieve. – jcuenod Jul 28 '15 at 15:11