263

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.

Brock Adams
  • 90,639
  • 22
  • 233
  • 295
JacobTheDev
  • 17,318
  • 25
  • 95
  • 158
  • 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. – ralph.m Jun 06 '13 at 02: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. – JacobTheDev Jun 06 '13 at 02:08
  • 2
    possible duplicate of [:not(:empty) CSS selector is not working?](http://stackoverflow.com/questions/8639282/notempty-css-selector-is-not-working) – Danny Beckett Jun 06 '13 at 02:10

18 Answers18

376

You can use the :placeholder-shown pseudo class. Technically a placeholder is required, but you can use a space instead.

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=" " />
redbmk
  • 4,687
  • 3
  • 25
  • 49
ngryman
  • 7,112
  • 2
  • 26
  • 23
  • 10
    This is not supported at all by IE or Firefox unfortunately. Source: http://caniuse.com/#feat=css-placeholder-shown – Sean Dawson Feb 22 '16 at 23:38
  • 4
    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. – corysimmons Feb 26 '16 at 03:35
  • 8
    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 `` even if there is no value. – redbmk Jun 11 '16 at 10:56
  • 7
    For me it works in Chrome, Firefox and Safari. Not in IE11. – J0ANMM Mar 03 '17 at 16:18
  • 2
    @redbmk as corysimmons mentioned, It should be noted that you can pass a space to a placeholder and this method will still work. – Naeem Baghi Feb 05 '18 at 13:01
  • As of Feb 2018, the only major browser not supporting it is Edge. Even mobile has support for this solution now. – Claudio Holanda Feb 23 '18 at 14:12
  • 1
    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) – Ben Racicot Mar 08 '19 at 20:25
  • 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. – johntrepreneur Jun 02 '20 at 21:20
  • 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](https://caniuse.com/css-placeholder-shown)) – Sygmoral Jan 31 '21 at 10:30
  • edge support now? – SuperUberDuper Aug 19 '22 at 10:47
304

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.

Jukka K. Korpela
  • 195,524
  • 37
  • 270
  • 390
  • 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. – Brock Adams Jun 06 '13 at 08:41
  • 9
    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 – AdamSchuld Apr 04 '15 at 18:15
  • 9
    this is dirty but wonderfully clever. Not a solution to the question, but it sure did the trick for me – Jan Jul 07 '15 at 16:07
  • 1
    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 – Artjom Kurapov Dec 12 '16 at 09:55
  • 2
    Semantically this is wrong. As mentioned in previous comments, some inputs may be optional, and the `required` attribute can prevent form submission. – zhenming Apr 10 '18 at 08:56
  • 5
    Added `novalidate` attribute on `
    `element so that no worry about red display when field empty after filled once: `
    `
    – Alcalyn May 28 '19 at 16:21
  • 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. – johntrepreneur Jun 02 '20 at 21:20
  • :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? – A.Raza Nov 19 '20 at 10:43
  • 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. – Jukka K. Korpela Nov 20 '20 at 19:54
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";
}
jpaugh
  • 6,634
  • 4
  • 38
  • 90
Brock Adams
  • 90,639
  • 22
  • 233
  • 295
  • I'll look in to that userscript thing. Thanks. – JacobTheDev Jun 06 '13 at 13:34
  • @MartinGottweis, not in the OP's case it doesn't. This is a *[stylish]* question. – Brock Adams May 20 '16 at 09:00
  • 1
    @BrockAdams, op is saying it can't use javascript, so the :valid option is a way to go. Am i missing something? – Martin Gottweis May 20 '16 at 09:15
  • 2
    @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. – Brock Adams May 20 '16 at 09:50
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;}
Fábio ZC
  • 798
  • 7
  • 10
  • 1
    You clearly just gave use the working solution and you've got 0 up-votes WaT? – ProNOOB Jul 30 '17 at 15:27
  • 5
    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! – Aaron Martin-Colby Nov 07 '17 at 19:29
  • 2
    It's not a pure css solution if you have to add "required" to your html – user1566694 Nov 08 '17 at 22:52
  • For IE10 and IE11, add `:-ms-input-placeholder` instead. Edge supports `:placeholder-shown` since 2019. – Sygmoral Jan 31 '21 at 10:26
32
<input onkeyup="this.setAttribute('value', this.value);" />

and

input[value=""]

will work :-)

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

Tom D.
  • 369
  • 3
  • 4
  • 32
    Is that CSS? It looks like HTML and Javascript (but I could be mistaken). – jww Jun 17 '14 at 08:18
  • 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: http://jsfiddle.net/XwZR2/ – Tom D. Jun 17 '14 at 11:57
  • 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. – John Weisz Feb 18 '15 at 16:21
  • 2
    @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. – Dinoboff Mar 27 '15 at 23:03
  • 2
    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. – beluga Nov 25 '15 at 18:51
  • 4
    `input[value]:not([value=""])` - is better. Thanks to all. http://codepen.io/iegik/pen/ObZpqo – iegik Dec 07 '16 at 02:37
  • 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. – J0ANMM Mar 03 '17 at 15:47
  • I would go for the onchange event but the one-line javascript approach is actually a very nice way to go. – dkellner Nov 18 '19 at 21:35
32

You can take advantage of the placeholder and use:

input:not(:placeholder-shown) {
  border: 1px solid red;
}
Scottyzen
  • 321
  • 4
  • 7
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

Yukulélé
  • 15,644
  • 10
  • 70
  • 94
Ricky Levi
  • 7,298
  • 1
  • 57
  • 65
  • 1
    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. – Stephen Tuttlebee Nov 28 '19 at 19:10
  • @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. – Ricky Levi Jul 11 '21 at 13:39
22

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
}
Kos
  • 1,547
  • 14
  • 23
15

Simple css:

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

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

Breno Teixeira
  • 3,860
  • 2
  • 19
  • 17
13

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>
benhatsor
  • 1,863
  • 6
  • 20
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

vbraun
  • 1,851
  • 17
  • 14
  • 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. – John Weisz Feb 18 '15 at 16:19
  • All of CSS is a cheap illusion, you only change appearances without affecting the actual content :-) – vbraun Feb 18 '15 at 23:47
  • 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! – Christopher Marshall Mar 18 '15 at 14:46
  • This works for backgrounds, but not borders. I didn't dig too deep into trying to change the border though. – majinnaibu Jun 02 '15 at 20:56
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="" />

   
Pavlo Kozachuk
  • 244
  • 3
  • 7
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
}
Niels Steenbeek
  • 4,692
  • 2
  • 41
  • 50
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.

Xedret
  • 1,823
  • 18
  • 25
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;
    }
Bren1818
  • 2,612
  • 1
  • 23
  • 28
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;
}
Hidayt Rahman
  • 2,490
  • 26
  • 32
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);
}
-7

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

Logan
  • 23
  • 5
  • 2
    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. – JacobTheDev Jun 06 '13 at 02:13