291

Is there a way to detect whether or not an input has text in it via CSS? I've tried using the :empty pseudo-class, and I've tried using [value=""], neither of which worked. I can't seem to find a single solution to this.

I imagine this must be possible, considering we have pseudo-classes for :checked, and :indeterminate, both of which are kind of similar thing.

Please note: I'm doing this for a "Stylish" style, which can't utilize JavaScript.

Also note, that Stylish is used, client-side, on pages that the user does not control.

3
  • I'm not sure of a way to do it with CSS (which doesn't update on the fly, anyway). This is easy with JavaScript, though. Commented Jun 6, 2013 at 2:06
  • I don't think I can use JavaScript. I'm working on a "stylish" style. Pretty sure it has to be done entirely with CSS. If it wouldn't update as the user enters text, I guess this is kind of a waste of time then. Didn't think about that. Hmm. At least this isn't critical for the style, it's just a nicety I was hoping to add. Commented Jun 6, 2013 at 2:08
  • 2
    possible duplicate of :not(:empty) CSS selector is not working? Commented Jun 6, 2013 at 2:10

19 Answers 19

431

If your element has a placeholder attribute, you can use the :placeholder-shown pseudo class.

The placeholder attribute is required and can't be blank, but you can use a single space.

input:not(:placeholder-shown) {
  border-color: green;
}

input:placeholder-shown {
  border-color: red;
}
<input placeholder="Text is required" />
<input placeholder=" " value="This one is valid" />
<input placeholder=" " />

The :placeholder-shown property is supported in 97% of browsers and generally safe to use. With the right prefixes, it can even work in IE10.

Sign up to request clarification or add additional context in comments.

9 Comments

Awesome answer. Browser support sucks, but if a polyfill comes out for :placeholder-shown then this should become the accepted answer. The required method doesn't take into account fringe cases. It should be noted that you can pass a space to a placeholder and this method will still work. Kudos.
The other downside to this is you seem to need to actually have a placeholder. In other words, input:not(:placeholder-shown) will always match <input/> even if there is no value.
For me it works in Chrome, Firefox and Safari. Not in IE11.
@redbmk as corysimmons mentioned, It should be noted that you can pass a space to a placeholder and this method will still work.
I would say this is the answer and write fallback CSS for Edge. The required attribute with input:valid for Edge. (if you need this to work with non-required inputs on Edge you'll need JS to get it there)
|
310

It is possible, with the usual CSS caveats and if the HTML code can be modified. If you add the required attribute to the element, then the element will match :invalid or :valid according to whether the value of the control is empty or not. If the element has no value attribute (or it has value=""), the value of the control is initially empty and becomes nonempty when any character (even a space) is entered.

Example:

<style>
#foo { background: yellow; }
#foo:valid { outline: solid blue 2px; }
#foo:invalid { outline: solid red 2px; }
</style>
<input id=foo required>

The pseudo-classed :valid and :invalid are defined in Working Draft level CSS documents only, but support is rather widespread in browsers, except that in IE, it came with IE 10.

If you would like to make “empty” include values that consist of spaces only, you can add the attribute pattern=.*\S.*.

There is (currently) no CSS selector for detecting directly whether an input control has a nonempty value, so we need to do it indirectly, as described above.

Generally, CSS selectors refer to markup or, in some cases, to element properties as set with scripting (client-side JavaScript), rather than user actions. For example, :empty matches element with empty content in markup; all input elements are unavoidably empty in this sense. The selector [value=""] tests whether the element has the value attribute in markup and has the empty string as its value. And :checked and :indeterminate are similar things. They are not affected by actual user input.

9 Comments

This is is a great solution if and only if every input is required-- if not, you run into a situation where you have an empty yet valid input field unaffected by the invalid style. JS is probably the winner for this solution
this is dirty but wonderfully clever. Not a solution to the question, but it sure did the trick for me
Dirty solution. Note that this may cause problems with autocomplete in Chrome if you try to add label display logic based on this OR if input is actually not required and form has validation based on this
Semantically this is wrong. As mentioned in previous comments, some inputs may be optional, and the required attribute can prevent form submission.
Added novalidate attribute on <form>element so that no worry about red display when field empty after filled once: <form ... novalidate> <input ... required /> </form>
|
75

Stylish cannot do this because CSS cannot do this. CSS has no (pseudo) selectors for <input> value(s). See:

The :empty selector refers only to child nodes, not input values.
[value=""] does work; but only for the initial state. This is because a node's value attribute (that CSS sees), is not the same as the node's value property (Changed by the user or DOM javascript, and submitted as form data).

Unless you care only about the initial state, you must use a userscript or Greasemonkey script. Fortunately this is not hard. The following script will work in Chrome, or Firefox with Greasemonkey or Scriptish installed, or in any browser that supports userscripts (i.e. most browsers, except IE).

See a demo of the limits of CSS plus the javascript solution at this jsBin page.

// ==UserScript==
// @name     _Dynamically style inputs based on whether they are blank.
// @include  http://YOUR_SERVER.COM/YOUR_PATH/*
// @grant    GM_addStyle
// ==/UserScript==
/*- The @grant directive is needed to work around a design change
    introduced in GM 1.0.   It restores the sandbox.
*/

var inpsToMonitor = document.querySelectorAll (
    "form[name='JustCSS'] input[name^='inp']"
);
for (var J = inpsToMonitor.length - 1;  J >= 0;  --J) {
    inpsToMonitor[J].addEventListener ("change",    adjustStyling, false);
    inpsToMonitor[J].addEventListener ("keyup",     adjustStyling, false);
    inpsToMonitor[J].addEventListener ("focus",     adjustStyling, false);
    inpsToMonitor[J].addEventListener ("blur",      adjustStyling, false);
    inpsToMonitor[J].addEventListener ("mousedown", adjustStyling, false);

    //-- Initial update. note that IE support is NOT needed.
    var evt = document.createEvent ("HTMLEvents");
    evt.initEvent ("change", false, true);
    inpsToMonitor[J].dispatchEvent (evt);
}

function adjustStyling (zEvent) {
    var inpVal  = zEvent.target.value;
    if (inpVal  &&  inpVal.replace (/^\s+|\s+$/g, "") )
        zEvent.target.style.background = "lime";
    else
        zEvent.target.style.background = "inherit";
}

4 Comments

I'll look in to that userscript thing. Thanks.
@MartinGottweis, not in the OP's case it doesn't. This is a [stylish] question.
@BrockAdams, op is saying it can't use javascript, so the :valid option is a way to go. Am i missing something?
@MartinGottweis, the :valid option requires rewriting the page -- which is something the OP can't do with Stylish and that none of the other answers show at all in a browsing context. The user has no control over the page he is visiting.
43

Basically what everybody is looking for is:

LESS:

input:focus:required{
    &:invalid{ color: red; border-color: red; box-shadow: 0 0 6px red;}
    &:valid,
    &:placeholder-shown{ border-color: green; box-shadow: 0 0 8px green;}
}

Pure CSS:

input:focus:required:invalid{ color: red; border-color: red; box-shadow: 0 0 6px red;}
input:focus:required:valid,
input:focus:required:placeholder-shown{ border-color: green; box-shadow: 0 0 8px green;}

4 Comments

You clearly just gave use the working solution and you've got 0 up-votes WaT?
Awesome answer. The :placeholder-shown pseudo-class doesn't work in IE or Edge, though, so it's not a complete solution. It's damned close, though, and it makes me want to murder Edge for not supporting it. IE I could accept, but Edge? C'mon Microsoft!
It's not a pure css solution if you have to add "required" to your html
For IE10 and IE11, add :-ms-input-placeholder instead. Edge supports :placeholder-shown since 2019.
33

You can take advantage of the placeholder and use:

input:not(:placeholder-shown) {
  border: 1px solid red;
}

Comments

32
<input onkeyup="this.setAttribute('value', this.value);" />

and

input[value=""]

will work :-)

edit: http://jsfiddle.net/XwZR2/

8 Comments

Is that CSS? It looks like HTML and Javascript (but I could be mistaken).
Brook Adams wrote: [value=""] does work; but only for the initial state. This is because a node's value attribute (that CSS sees), is not the same as the node's value property (Changed by the user or DOM javascript, and submitted as form data). --> The magic is to update the value attribute on changes: jsfiddle.net/XwZR2
@JánosWeisz no it won't. That handler will be set before a script can manipulate that element and it can work along handler added with addEventListener.
Obviously, onkeyup takes care of keyboard input only. Don't forget, however, that you can paste text into an input box using your mouse. Try it out: Copy some text into your clipboard and then right-click on the input and click Paste. Watch the CSS NOT working. Same with text drag-and-drop into the input box with your mouse.
input[value]:not([value=""]) - is better. Thanks to all. codepen.io/iegik/pen/ObZpqo
|
30

You can use the placeholder trick as written above w/o required field.

The problem with required is that when you wrote something, then deleted it - the input will now always be red as part of the HTML5 spec - then you'll need a CSS as written above to fix/override it.

You can simple do thing w/o required

<input type="text" placeholder="filter here" id="mytest" />

CSS

#mytest:placeholder-shown {
/* if placeholder is shown - meaning - no value in input */
  border: black 1px solid;
  color: black;
}
#mytest {
  /* placeholder isn't shown - we have a value in input */
  border: red 1px solid;
  color: red;
}

Code pen:https://codepen.io/arlevi/pen/LBgXjZ

2 Comments

This approach was a perfect fit for my use case. I had search filters which had placeholders anyway, and I wanted the input box's border to be highlighted when a value was present.
@barhatsor mm i don't remember, but in web & languages things moving and changing very fast. but the fact that people still vote for this answer - i guess they probably receive the same behavior as i did ( that it turns red when you write something then delete - this is why i added my answer on top of the official answer). I saw your answer below - the author of this post though, didn't want the required - he just want to know if there's anything inside an input field, adding the required turns on form validation- and that is something that I personally didn't want.
26

Using attribute placeholder and pseudo class placeholder-shown is proper way of detecting does input has text.

Example:

<input type="email" placeholder=" " required>
<label>Email</label>
input:focus ~ label,
input:not(:placeholder-shown) ~ label
{
  top : -4em
  left : -0.2em
  font-size : 0.9em
}

1 Comment

This is perfect! input:not(:placeholder-shown)
16

Simple css:

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

This code is going to apply the given css on page load if the input is filled up.

2 Comments

This only works on page load. Not dynamic typing a value.
Page load issue should be explicit noted for this answer.
16

There's actually a way to do this without JavaScript.

If you set an <input>'s required selector to true, you can check if there's text in it with the CSS :valid tag.

References:

MDN Docs
CSS Tricks

input {
  background: red;
}

input:valid {
  background: lightgreen;
}
<input type="text" required>

4 Comments

I know it's late but... what if the input has a type of text, therefore the box will never get a green background unless its an like [email protected]
To check for an email address, swap type="text" to type="email".
textarea:placeholder-shown { border-color: red; } will enable you. No javascript required
That won't work if the input has no placeholder.
6

You can style input[type=text] differently depending on whether or not the input has text by styling the placeholder. This is not an official standard at this point but has wide browser support, though with different prefixes:

input[type=text] {
    color: red;
}
input[type=text]:-moz-placeholder {
    color: green;
}
input[type=text]::-moz-placeholder {
    color: green;
}
input[type=text]:-ms-input-placeholder {
    color: green;
}
input[type=text]::-webkit-input-placeholder {
    color: green;
}

Example: http://fiddlesalad.com/scss/input-placeholder-css

4 Comments

FYI, this reliably formats the placeholder, but only the placeholder itself. This gives you an illusion of changing text color, but that is already the case, just with gray and black by default.
All of CSS is a cheap illusion, you only change appearances without affecting the actual content :-)
This is exactly what I needed. I required the input to change styles if it had text as the design for the placeholder differs from the input style. Perfect!
This works for backgrounds, but not borders. I didn't dig too deep into trying to change the border though.
6

Using JS and CSS :not pseudoclass

 input {
        font-size: 13px;
        padding: 5px;
        width: 100px;
    }

    input[value=""] {
        border: 2px solid #fa0000;
    }

    input:not([value=""]) {
        border: 2px solid #fafa00;
    }
<input type="text" onkeyup="this.setAttribute('value', this.value);" value="" />

   

Comments

4

The valid selector will do the trick.

<input type="text" class="myText" required="required" />

.myText {
    //default style of input
}
.myText:valid {
    //style when input has text
}

Comments

2

Simple Trick with jQuery and CSS Like so:

JQuery:

$('input[value=""]').addClass('empty');
        $('input').keyup(function(){
            if( $(this).val() == ""){
                $(this).addClass("empty");
            }else{
                $(this).removeClass("empty");
            }
        });

CSS:

input.empty:valid{
        box-shadow: none;
        background-image: none;
        border: 1px solid #000;
    }

    input:invalid,
    input:required {
        box-shadow: 3px 1px 5px rgba(200, 0, 0, 0.85);
        border: 1px solid rgb(200,0,0);
    }




    input:valid{
        box-shadow: none;
        border: 1px solid #0f0;
    }

Comments

1

do it on the HTML part like this:

<input type="text" name="Example" placeholder="Example" required/>

The required parameter will require it to have text in the input field in order to be valid.

5 Comments

This does not help to detect whether input has text in it with CSS, which was the question.
Sorry, it actually helps... It makes it possible to use pseudo-classes, as explained in my answer.
This is a Stylish question -- which means that the OP cannot control or alter the target page. He only sees the page client-side.
This was super helpful, here's an example of what Xedret is talking about: codepen.io/tolmark12/pen/LsBvf
****** <input required> && input:valid { ... } ******
0

Yes! you can do it with simple basic attribute with value selector.

Use attribute selector with blank value and apply properties input[value='']

input[value=''] {
    background: red;
}

Comments

0

It's here, .fase is a class of input in html code.

div.fase > input:focus:required:invalid { 
    color: red;
    border-color: red; 
    box-shadow: 0 0 6px red;
}

div.fase input:focus:required:valid,
input:focus:required:placeholder-shown {
    border-color: rgb(22, 172, 22);
    box-shadow: 0 0 8px rgb(28, 150, 28);
}

div.fase input:valid {
    border-color: rgb(47, 148, 49);
}

Comments

0

If you guys are not looking for just pure css, then just add this to your script to add a class to the inputs with values in them.`

// add a field filled class
  const inputs = document.querySelectorAll("input");
  inputs.forEach((el) => {
    el.addEventListener("blur", (e) => {
      const element = e.target;
      const { value } = element;
      if (value.length > 0) {
        element.classList.add("hasValue");
      } else {
        element.classList.remove("hasValue");
      }
    });
  });

`

Comments

-8

This is not possible with css. To implement this you will have to use JavaScript (e.g. $("#input").val() == "").

1 Comment

I know how to do that, I need to do it with CSS. Please read the comments on the original post. I'm building a "Stylish" style, which can't utilize JavaScript, to my knowledge.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.