2

Can we change the text content of a HTML5 placeholder using only CSS ?

I tried using the content : '' but it does not seem to help.

<input type="text" class="zip" placeholder="Enter Zip" />

input{
    &:placeholder{
       content:'Search by name'
    }
}
Cody Guldner
  • 2,888
  • 1
  • 25
  • 36
Sushanth --
  • 55,259
  • 9
  • 66
  • 105
  • You can work it to a degree. I've got something to work in Chrome so far. Give me a minute. – Jared Farrish Mar 09 '13 at 18:24
  • @JaredFarrish Could you ping me when you finish? I'd like to see it. I can think of a couple ways to sort of do it but they are all impractical/stupid. – Wesley Murch Mar 09 '13 at 18:33
  • Example of stupid impractical hack that doesn't work very well: http://jsfiddle.net/6UqQN/ – Wesley Murch Mar 09 '13 at 18:41
  • @WesleyMurch - Oh yeah, this is trying to hack Firefox's innards, plug `resource://gre-resources/forms.css` in Firefox and look for the `::-moz-placehoder` pseudo-element. Unfortunately, you can't access `:before` or `:after`, so `:content` doesn't look exposed here. Now... [*in Chrome*](http://jsfiddle.net/LDkjW/) ... What have I done? `:o` So it's fairly easy in Chrome, just set the pseudo-element's `font-size` to 0, *give* a `font-size` to `:before` and/or `:after`, and voila. Also, using `white-space: pre`, you can nudge that line out of sight too and pair with `:before/:after` as well. – Jared Farrish Mar 09 '13 at 20:02
  • @JaredFarrish I think that comment is answer-worthy and quite valuable even if it isn't perfection. Ping me if you do and you have my vote. – Wesley Murch Mar 09 '13 at 20:43

3 Answers3

6

You can use the following pseudo-elements (note the terminology) in webkit-based, Firefox and IE browsers of later vintage:

// Note two colons, -input-
::-webkit-input-placeholder

// Note two colons, NO -input-
::-moz-placeholder

// Note ONE colon, -input-
:-ms-input-placeholder

This particular "functionality" associated with this one attribute seems to be evolving, so this answer may eventually become dated. These are vendor-prefixed, after all.

What I did find is in webkit-based browsers, you can treat this attribute as a pseudo-element (more below on that), to the point you can manipulate it's CSS content with :before and :after in such a way that it appears you've changed the placeholder. With Firefox, at least right now, that's not possible (also more later). With IE9 (the only version I tested), it did not appear to work.

The following works only in Chrome:

Markup

<input type="text" class="before" placeholder="Wide "/><br/>
<input type="text" placeholder="Wide "/><br/>
<input type="text" placeholder="Wide "/>

CSS

.before::-webkit-input-placeholder:before {
    content: 'Hello \A';
    font-size: 12px;
    color: red;
}
::-webkit-input-placeholder:before {
    content: 'Hello ';
    font-size: 12px;
    color: red;
}
::-webkit-input-placeholder {
    white-space: pre;
    font-size: 5px;
}
::-webkit-input-placeholder:after {
    content: 'World';
    font-size: 12px;
    color: blue;
}

http://jsfiddle.net/LDkjW/

Note there's two :befores in there, showing two methods, one with the \A newline which works in CSS, and also a bracketed :before and :after if you're interested. As you can agree, the :after isn't very useful if you've used \A with :before.

Note, browsers freak out if you have a pseudo-selector it doesn't recognize, so if you decide to include the others, you should do each vendor's in it's own block. In addition, you'll see the lack of -input- on the -moz (Firefox) pseudo-element. That's because (ta-da) textarea's also get the placeholder treatment. And at least Chrome (IE?) does also apply this to textareas. Why -input- is in there, who knows.

That's it. I don't know how this is intended to be used, but I suspect it's probably best done another way. If webkit browsers are all you care about, you're good. Otherwise, maybe one day... The rest is just excessive.


Firefox

You can "remove from view" the placeholder fairly easily in Firefox:

::-moz-placeholder {
    font-size: 0;
    left-indent: -1000px;
    font-color: white;
}

You get the idea. ::-moz-placeholder was :-moz-placeholder until recently, which it was given the new selector moniker. Let's take a closer look.

:-moz-placeholder  // Legacy
::-moz-placeholder // As of FF17

One : indicates by convention that this references a state of the selected element. Your hovers, :link, visited, :focused, as well as the more useful CSS3 pseudo-selectors such as :nth-child, :selected, :checked, etc.

This ::-moz-placeholder being a pseudo-element, it's not observing a state or condition of an element, it's representing an element. A pseudo element. Where are we headed with this, you might be thinking.

From what it appears to be, an input is not what it appears to be. For instance:

http://dxr.mozilla.org/mozilla-central/layout/style/forms.css.html

Which you can access through Firefox's address bar using:

resource://gre-resources/forms.css

We find things like:

input > .anonymous-div,
input::-moz-placeholder {
  word-wrap: normal !important;
  /* Make the line-height equal to the available height */
  line-height: -moz-block-height;
}

And:

textarea > .anonymous-div,
input > .anonymous-div,
input::-moz-placeholder,
textarea::-moz-placeholder {
  white-space: pre;
  overflow: auto;
   ...
  -moz-text-decoration-color: inherit;
  -moz-text-decoration-style: inherit;
  display: inline-block;
  ime-mode: inherit;
  resize: inherit;
}
textarea > .anonymous-div.wrap,
input > .anonymous-div.wrap {
  white-space: pre-wrap;
}
textarea > .anonymous-div.inherit-overflow,
input > .anonymous-div.inherit-overflow {
  overflow: inherit;
}
input::-moz-placeholder,
textarea::-moz-placeholder {
  /*
   * Changing display to inline can leads to broken behaviour and will assert.
   */
  display: inline-block !important;
  /*
   * Changing resize would display a broken behaviour and will assert.
   */
  resize: none !important;
  overflow: hidden !important;
  /*
   * The placeholder should be ignored by pointer otherwise, we might have some
   * unexpected behavior like the resize handle not being selectable.
   */
  pointer-events: none !important;
  opacity: 0.54;
}

I'm sure you've noticed the input::-moz-placeholder (?) and the textarea is also part of the fun. But did you notice this?

textarea > .anonymous-div,
input > .anonymous-div,

.anonymous-div? What the heck is that? Whatever it is, the selector indicates it's within the input/textarea element. Really?

Later, the unusual truth comes out:

 /*
  * Make form controls inherit 'unicode-bidi' transparently as required by
  *  their various anonymous descendants and pseudo-elements:
  *
  * <textarea> and <input type="text">:
  *  inherit into the XULScroll frame with class 'anonymous-div' which is a
  *  child of the text control.
  *
  * Buttons (either <button>, <input type="submit">, <input type="button">
  *          or <input type="reset">)
  *  inherit into the ':-moz-button-content' pseudo-element.
  *
  * <select>:
  *  inherit into the ':-moz-display-comboboxcontrol-frame' pseudo-element and
  *  the <optgroup>'s ':before' pseudo-element, which is where the label of
  *  the <optgroup> gets displayed. The <option>s don't use anonymous boxes,
  *  so they need no special rules.
  */
textarea > .anonymous-div,
input > .anonymous-div,
input::-moz-placeholder,
textarea::-moz-placeholder,
*|*::-moz-button-content,
*|*::-moz-display-comboboxcontrol-frame,
optgroup:before {
  unicode-bidi: inherit;
  text-overflow: inherit;
}

So there you go. There's an "anonymous" (div) embedded within all textarea and input[type=text] elements you work with. Here's some XUL that seems plausibly similar to what is probably going on right under our noses:

XUL

<box id="num" class="labeledbutton" title="Number of Things:" value="52"/>

<button label="Show" oncommand="document.getElementById('num').showTitle(true)"/>
<button label="Hide" oncommand="document.getElementById('num').showTitle(false)"/>

XBL

<binding id="labeledbutton">
  <content>
    <xul:label xbl:inherits="value=title"/>
    <xul:label xbl:inherits="value"/>
  </content>
  <implementation>
    <method name="showTitle">
      <parameter name="state"/>
      <body>
        if (state) document.getAnonymousNodes(this)[0].
          setAttribute("style","visibility: visible");
        else document.getAnonymousNodes(this)[0].
          setAttribute("style","visibility: collapse");
      </body>
    </method>
  </implementation>
</binding>

Unfortunately, the manner in which Firefox deals with this "anonymous" gang of pseudo-elements means you probably won't be able to manipulate the placeholder's text like we did in Chrome.

And just now I found the XUL/XBL markup that includes the input and placeholder mechanism/definition. Here it is:

  <property name="label" onset="this.setAttribute('label', val); return val;"
                         onget="return this.getAttribute('label') ||
                                        (this.labelElement ? this.labelElement.value :
                                         this.placeholder);"/>
  <property name="placeholder" onset="this.inputField.placeholder = val; return val;"
                               onget="return this.inputField.placeholder;"/>
  <property name="emptyText" onset="this.placeholder = val; return val;"
                             onget="return this.placeholder;"/>

Which handles the placeholder swapping. The following shows in the .anonymous-div, which appears to get swapped out with some code from the core. I'll spare you those gory details.

  <binding id="input-box">
    <content context="_child">
      <children/>
      ...
    </content>

These last two blocks I found within:

jar:file:///C:/path/to/a/FirefoxPortable/App/firefox/omni.ja!/chrome/toolkit/content/global/bindings/textbox.xml

If you're interested in getting into Firefox's business on this (or in general), try this if you're interesting in getting into more of the actual chrome HTML and CSS files:

resource://gre-resources/

You can read more on ::-webkit-input-placeholder or ::-moz-placeholder in this question. Take note that this particular type of selector (pseudo-element, not pseudo class... at least lately...) is somewhat brittle in the way you approach using them in stylesheets.

http://dxr.mozilla.org/mozilla-central/layout/style/forms.css.html

Phew. Never thought this snipe hunt was going to end. Hope that helps somebody. I learned some things, like the context menu over the input[type=text] elements is hardcoded into the XUL code with the element markup definition. Another surprise.

Anyhow, good luck.

Community
  • 1
  • 1
Jared Farrish
  • 48,585
  • 17
  • 95
  • 104
  • TL;DR but you have my vote all the same. Looks like you've been deep in the belly of the beast. This vendor specific stuff is so fleeting and limited in use, it's hard for me to be genuinely interested. Chrome especially is a strange animal sometimes. – Wesley Murch Mar 09 '13 at 23:24
  • @Jared Farrish .. Great work for digging in deep, but at the moment this looks greek to me . :) .. I will try to dig in and research the info that you have provided .. Thanks – Sushanth -- Mar 10 '13 at 01:24
  • @mog - I cleaned the opening up and indicate where the answer ends and the "extended details" begin. Yeah, I've had a [peculiar fascination](http://stackoverflow.com/questions/12450755/save-source-of-popup-window-as-string/12454721#12454721) with getting inside the browser once I figured out I could. I probably also have a little bit of interest that I won't go into. I find it interesting, at least. Also, Mog? – Jared Farrish Mar 11 '13 at 02:31
  • @Sushanth-- - I made the answer more clear (it only works on webkit browsers). The rest is *why* it doesn't work on Firefox, plus some other things I discovered while researching it. HTH. – Jared Farrish Mar 11 '13 at 03:40
  • @Sushanth-- - This fiddle is fairly close to how Firefox (and I believe Chrome) handles an `input` (and `textarea`): http://jsfiddle.net/userdude/3AdD7/ The `#textbox` would be the `input`, the inner elements the hidden parts of the `input`. Note, only tested in Chrome and not (really) production ready in any way. Just a demo. – Jared Farrish Mar 11 '13 at 17:37
2

Using only CSS it is not possible to do this literally. Your attempt is a bit off too, placeholder is not an element but rather an attribute, and the content property is only used with :before and :after properties, which input does not support. (also you have a mistake in your spelling placehodler)

The best approach would be to change it in the markup, or if that's not possible, with javascript:

yourElementSelector.placeholder = 'Search by name';
Wesley Murch
  • 101,186
  • 37
  • 194
  • 228
  • Thanks for pointing out the finer points that I have missed.. Currently I am using javascript to get the things done. So was wondering if there was a way out by using plain `CSS` . That hack you tried was really good one. But .. – Sushanth -- Mar 09 '13 at 20:41
  • Well... @Sushanth--, *placeholder is not an element but an attribute* is, unbelievably, *inaccurate*. Maybe it works different than we think it would or should. It turns out that yes, **`::-moz-placeholder` is a `DIV`** within an `input`. And there's possibly *another* element *within* that seemingly untouchable (in Firefox) `.anonymous-div` low-level container for `placeholder`. In Chrome, it seems `:before` and `:after` may actually append new nodes to the pseudo-element `::-webkit-input-placeholder`. So Wesley's "goofy" fiddle is more literal than we guessed. I'll write it up. – Jared Farrish Mar 09 '13 at 21:02
  • @JaredFarrish I get what you're saying, but it's technically accurate. A browser may *generate* an element, but `placeholder` itself is not an HTML element. The reason I said it in the first place is because I read the OP's LESS/SASS code wrong, it's actually using `input:placeholder` and not `input placeholder` as I thought. In any case, CSS is not the best way to change placeholder text, but it appears it *can* be done. – Wesley Murch Mar 09 '13 at 21:32
  • I posted the results of my unfortunately somewhat exhaustive research. It's a bit different that I thought beneath ol' Firefox's hood. Short answer: An input is a nested series of HTML and XUL elements. – Jared Farrish Mar 09 '13 at 23:23
-1

No. Can you imagine changing the value of a field using CSS ?

What you expect, is same as this. You should use javascript.

hop
  • 2,518
  • 11
  • 40
  • 56