Trying to add generated-content to HTML form fields

Objective

What I am trying to do is use HTML like this (I’m removing a bunch of stuff for brevity)…

<input required />

… and CSS like this…

input[required]::before {
	content: '*';
	position: absolute;
	top: 0;
	left: 1em;
	color: red;
}

… to get something that looks like this…
Trying to use generated-content with html form fields
… without having to resort to extraneous JavaScript or HTML.

Attempt

Try viewing this demo page in your favorite browser(s). The HTML for each form element is beside the form element itself and the CSS used is (essentially) that which is displayed above.
Demo

Outcome

This doesn’t seem reliably possible, in any modern browser… Which is really amazingly wrong to me…

The generated-content that I want to add is purely presentational, doing nothing more than displaying an indicator to the user so they know which fields they are required to complete. There is nothing semantic about it. This means it should be 100% “CSSable”, not requiring any extra JS or HTML. But, in the latest installation of Chrome 1, FF, IE, Opera, and Safari 2, nothing is added to the page…

Inspecting the elements that do and don’t display the generated-content in Chrome DevTools, you will see that the elements that do display the generated-content do not add any special document-fragment to the page, appearing in DevTools like this…

<input type="radio" required="">
	#document-fragment
	::before
</input>

… whereas the elements that do not display the generated-content, things like text-boxes and drop-downs, do add special document-fragment to the page, appearing in DevTools like this…

<input type="radio" required="">
	#document-fragment
	<div id="inner-editor"></div>
</input>

Note that special <div id="inner-editor"></div> in there, instead of my special ::before… It’s like DevTools is overwriting my generated-content with theirs?

Wrap-up

Based on the nearly perfect blocking of this behavior by all the major browsers, I would have to assume it is intentional (which would mean that the few elements that do allow this behavior in Chrome would have to be oversights?). Perhaps somewhere in the labyrinth that is the HTML/CSS Specs there is a bit saying browsers shouldn’t allow generated-content on form elements, for some reason. Maybe that reason even makes sense.

But to me, this is very frustrating, because this is a perfect example of what should be done via CSS, but cannot…

So, happy unnecessary-JS-or-HTML-adding,
Atg

1 Chrome actually does add the generated-content, but only for radio, checkbox, progress, color and file input types.

2 Update, :
These results are all on Windows 7 Pro, I will try to add iOS tests soon. In the mean time, I have been able to test the demo page on the following mobile device/browser combinations:

  • HTC Desire S, Android 2.3.5:
    • default browser: these work: radio, checkbox, and file
    • Firefox 27: nothing works
    • Opera Classic 12.10: nothing works
    • Opera Mini 7.5.3: They all work!! Except for select and textarea (even all the buttons worked!)
  • iPhone 4, iOS 6.1.3:
    • default Safari: They all work!! Except for select, textarea and file and any form of button :-/
    • Chrome 32: They all work!! Except for select, textarea and file and any form of button :-/
    • Opera Mini 7.0.5: They all work!! Except for select and textarea (even all the buttons worked!)

4 Responses to Trying to add generated-content to HTML form fields

  1. Yes this is per specification. Form elements and images are “replaced elements” https://developer.mozilla.org/en-US/docs/Web/CSS/Replaced_element – discussed in length here why it doesn’t work http://www.red-team-design.com/css-generated-content-replaced-elements. TL;DR – browsers have different ways of implementing replacing, and adding :after to that would have worsened that.

    • aarontgrogg says:

      Thanks, Chris, that second article is a gem, especially when you get down to Lea’s and the others’ explanations.

      Doesn’t mean I like it, would be really great to be able to identify those required elements more easily, but at least I get it now…

      This quote from @chriscoyier really drove home the definition of :before and :after, which was not right in my head:

      It’s not “before” and “after” the element, it’s “before” and “after” the content inside the element.

      Cheers,
      Atg

  2. Joeytje50 says:

    The reason this doesn’t work is actually quite simple: The ::before and ::after pseudo-elements render inside its parent element. You could have found this via a fairly simple Google search, which would lead you to this StackOverflow answer.
     
    Basically, if you try to render a ::before pseudo-element inside a self-closing input element, then it won’t work, since you can’t nest any elements inside an input. It won’t work for select because everything nested inside those would have to render as an option, which is not what the ::before pseudo-element is.
     
    See this JSFiddle for a simple demonstration of the ::before pseudo-element’s position in the DOM. If you inspect the DOM via Chrome’s developer tools, you’ll also see how it renders: Inside the div

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.