Detect if an input has text in it using CSS -- on a page I am visiting and do not control?
Asked Answered
B

19

275

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.

Bedivere answered 6/6, 2013 at 1:56 Comment(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.Mucous
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.Bedivere
possible duplicate of :not(:empty) CSS selector is not working?Kommunarsk
B
74

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";
}
Burgos answered 6/6, 2013 at 8:34 Comment(4)
I'll look in to that userscript thing. Thanks.Bedivere
@MartinGottweis, not in the OP's case it doesn't. This is a [stylish] question.Burgos
@BrockAdams, op is saying it can't use javascript, so the :valid option is a way to go. Am i missing something?Emmet
@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.Burgos
A
396

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.

Advisee answered 9/2, 2016 at 21:39 Comment(9)
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.Biblio
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.Negligent
For me it works in Chrome, Firefox and Safari. Not in IE11.Rookery
@Negligent as corysimmons mentioned, It should be noted that you can pass a space to a placeholder and this method will still work.Bloodshed
As of Feb 2018, the only major browser not supporting it is Edge. Even mobile has support for this solution now.Aviator
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)Draconic
This only works if you're styling the input itself. Trying to style the input's label text won't work since the css selector will be referencing the input and apply the style to that instead of applying it to the label which would reside in a different css selector path.Endocrine
For what it's worth: IE10 and IE11 support it with :-ms-input-placeholder instead. All more recent browsers (including 'the new Edge' since 2020) support :placeholder-shown. (source: caniuse)Supersaturate
edge support now?Pneumonia
F
306

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.

Fab answered 6/6, 2013 at 7:55 Comment(9)
This is a Stylish question -- which means that the OP cannot control or alter the target page. He cannot add the required attribute, for example. He only sees the page client-side.Burgos
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 solutionSalmons
this is dirty but wonderfully clever. Not a solution to the question, but it sure did the trick for meDiverge
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 thisFast
Semantically this is wrong. As mentioned in previous comments, some inputs may be optional, and the required attribute can prevent form submission.Sivan
Added novalidate attribute on <form>element so that no worry about red display when field empty after filled once: <form ... novalidate> <input ... required /> </form>Crustal
This only works if you're styling the input itself. Trying to style the input's label text won't work since the css selector will be referencing the input and apply the style to that instead of applying it to the label which would reside in a different css selector path.Endocrine
:invalid or :valid are not working for textarea. I am trying textarea:valid but it simpley doesn't work. Is there some different approach for textarea?Matelda
A.Raza, I just tested this for textarea, on Chrome, Edge, and Android, and it worked like for input. Perhaps you tried with a textarea with some non-empty initial (default) content? The whole idea is to test whether the control has a value or not, and an initially set value is here indistinguishable from a user-supplied value.Fab
B
74

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";
}
Burgos answered 6/6, 2013 at 8:34 Comment(4)
I'll look in to that userscript thing. Thanks.Bedivere
@MartinGottweis, not in the OP's case it doesn't. This is a [stylish] question.Burgos
@BrockAdams, op is saying it can't use javascript, so the :valid option is a way to go. Am i missing something?Emmet
@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.Burgos
O
40

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;}
Omegaomelet answered 3/5, 2017 at 21:54 Comment(4)
You clearly just gave use the working solution and you've got 0 up-votes WaT?Consols
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!Tetreault
It's not a pure css solution if you have to add "required" to your htmlSubmarine
For IE10 and IE11, add :-ms-input-placeholder instead. Edge supports :placeholder-shown since 2019.Supersaturate
P
33

You can take advantage of the placeholder and use:

input:not(:placeholder-shown) {
  border: 1px solid red;
}
Programme answered 9/4, 2020 at 22:4 Comment(0)
C
32
<input onkeyup="this.setAttribute('value', this.value);" />

and

input[value=""]

will work :-)

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

Coly answered 17/6, 2014 at 7:57 Comment(8)
Is that CSS? It looks like HTML and Javascript (but I could be mistaken).Firkin
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/XwZR2Coly
I think this is one of the very few uses of well placed inline event handling, if you don't want to leak presentation logic into your JavaScript files, but don't mind cluttering up your HTML a bit. Keep in mind, however, that this will override all other event handlers that you previously attached to that element for the onkeyup event.Frugal
@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.Fonz
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.Underlay
input[value]:not([value=""]) - is better. Thanks to all. codepen.io/iegik/pen/ObZpqoMillenarianism
Very good point from beluga. I was struggling to understand why the jsfiddle was working and for me it was not, until I read his comment and realised I have a datepicker and therefore no keyboard input.Rookery
I would go for the onchange event but the one-line javascript approach is actually a very nice way to go.Athenaathenaeum
T
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

Tansey answered 8/8, 2018 at 8:47 Comment(2)
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.Prosperous
@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.Tansey
S
23

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
}
Spathic answered 17/7, 2021 at 11:0 Comment(1)
This is perfect! input:not(:placeholder-shown)Oisin
V
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.

Vantage answered 15/3, 2018 at 13:12 Comment(2)
This only works on page load. Not dynamic typing a value.Draconic
Page load issue should be explicit noted for this answer.Hocuspocus
K
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>
Kneepad answered 4/9, 2020 at 11:10 Comment(4)
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]Bain
To check for an email address, swap type="text" to type="email".Kneepad
textarea:placeholder-shown { border-color: red; } will enable you. No javascript requiredGreggs
That won't work if the input has no placeholder.Kneepad
I
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

Icicle answered 16/2, 2015 at 16:59 Comment(4)
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.Frugal
All of CSS is a cheap illusion, you only change appearances without affecting the actual content :-)Icicle
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!Lyse
This works for backgrounds, but not borders. I didn't dig too deep into trying to change the border though.Kevinkevina
E
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="" />

   
Egomania answered 27/10, 2016 at 11:8 Comment(0)
P
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
}
Pudency answered 26/9, 2016 at 12:32 Comment(0)
P
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.

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

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;
    }
Ashe answered 6/5, 2014 at 18:41 Comment(0)
C
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;
}
Coel answered 31/7, 2018 at 7:52 Comment(0)
P
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);
}
Placentation answered 23/12, 2022 at 0:0 Comment(0)
V
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");
      }
    });
  });

`

Vito answered 5/2, 2024 at 13:8 Comment(0)
A
-8

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

Arborization answered 6/6, 2013 at 2:12 Comment(1)
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.Bedivere

© 2022 - 2025 — McMap. All rights reserved.