Can I use a :before or :after pseudo-element on an input field?

587,090

Solution 1

:after and :before are not supported in Internet Explorer 7 and under, on any elements.

It's also not meant to be used on replaced elements such as form elements (inputs) and image elements.

In other words it's impossible with pure CSS.

However if using jquery you can use

$(".mystyle").after("add your smiley here");

API docs on .after

To append your content with javascript. This will work across all browsers.

Solution 2

:before and :after render inside a container

and <input> can not contain other elements.


Pseudo-elements can only be defined (or better said are only supported) on container elements. Because the way they are rendered is within the container itself as a child element. input can not contain other elements hence they're not supported. A button on the other hand that's also a form element supports them, because it's a container of other sub-elements.

If you ask me, if some browser does display these two pseudo-elements on non-container elements, it's a bug and a non-standard conformance. Specification directly talks about element content...

W3C specification

If we carefully read the specification it actually says that they are inserted inside a containing element:

Authors specify the style and location of generated content with the :before and :after pseudo-elements. As their names indicate, the :before and :after pseudo-elements specify the location of content before and after an element's document tree content. The 'content' property, in conjunction with these pseudo-elements, specifies what is inserted.

See? an element's document tree content. As I understand it this means within a container.

Solution 3

Oddly, it works with some types of input. At least in Chrome,

<input type="checkbox" />

works fine, same as

<input type="radio" />

It's just type=text and some others that don't work.

Solution 4

Here's another approach (assuming you have control of the HTML): add an empty <span></span> right after the input, and target that in CSS using input.mystyle + span:after

.field_with_errors {
  display: inline;
  color: red;
}
.field_with_errors input+span:after {
  content: "*"
}
<div class="field_with_errors">Label:</div>
<div class="field_with_errors">
  <input type="text" /><span></span> 
</div>

I'm using this approach in AngularJS because it will add .ng-invalid classes automatically to <input> form elements, and to the form, but not to the <label>.

Solution 5

:before and :after are applied inside a container, which means you can use it for elements with an end tag.

It doesn't apply for self-closing elements.

On a side note, elements which are self-closing (such as img/hr/input) are also known as 'Replaced Elements', as they are replaced with their respective content. "External Objects" for the lack of a better term. A better read here

Share:
587,090
matra
Author by

matra

SOreadytohelp

Updated on February 16, 2022

Comments

  • matra
    matra about 2 years

    I am trying to use the :after CSS pseudo-element on an input field, but it does not work. If I use it with a span, it works OK.

    <style type="text/css">
    .mystyle:after {content:url(smiley.gif);}
    .mystyle {color:red;}
    </style>
    

    This works (puts the smiley after "buu!" and before "some more")

    <span class="mystyle">buuu!</span>a some more
    

    This does not work - it only colors someValue in red, but there is no smiley.

    <input class="mystyle" type="text" value="someValue">
    

    What am I doing wrong? should I use another pseudo-selector?

    Note: I cannot add a span around my input, because it is being generated by a third-party control.

  • matra
    matra about 14 years
    Alex, I am using IE8 and latest FF, so IE7 is not an issue. I was seraching for any documentation about limiatation of :after, but was unable to find it. w3.org/TR/CSS2/generate.html states, that it is inserted after the current node in document tree so it should work in both cases.
  • Michele
    Michele about 14 years
    Unless you are building the page just for your own use a large percentage of the internet use those browsers still. The w3c spec says this yes; but as you well know browsers implement their own interpretation of the spec. Using :after on an input will only work in Opera 9+, but is not implemented in IE, FF, safari or chrome because of the way they internally construct the DOM - again it can't be done with pure CSS.
  • matra
    matra about 14 years
    Thanks for the answer (BTW: I am building intranet application which wil be used by few internal users)
  • coreyward
    coreyward over 13 years
    I'm not sure if this was the case in April, but Webkit does support :after in general, though it doesn't support either :before or :after on inputs.
  • Robert Koritnik
    Robert Koritnik over 13 years
    As far as I understand W3C :after and :before pseudo elements, they can only be put on container elements. Why? Because they are appended inside that particular element. input is not a container. button for instance is hence you can put them on. Works as expected. Specification actually says: before and after an element's document tree content It explicitly says CONTENT. So an element must be a container.
  • Pramod Prajapati
    Pramod Prajapati almost 13 years
    +1 Much better than the accepted answer. Thanks for the clear explanation of the standard itself. So much for [required]::before { content "*"; color: red; } :P
  • flu
    flu over 12 years
    Tip: If you're having the problem with just a submit input like <input type="submit" value="Send"/>, use <button type="submit">Send</button> instead. The presentation is identical but the <button> is a container and thus supports :beforeand :after.
  • deathlock
    deathlock over 11 years
    What about <hr />? I thought it wasn't a container element, but it could render :after and :before jsfiddle.net/Uf88j/1
  • Robert Koritnik
    Robert Koritnik over 11 years
    @deathlock: that is indeed interesting. I would say it must be some kind of an anomaly and I wouldn't rely on it working cross browser or cross versions... HR is not a container element hence should not allow for pseudo elements. Even W3C standard says that it allows no content. And if you check for void element you can see that these elements shouldn't have any content under any circumstances. Pseudo elements are content so expect future browser version to fail to display them.
  • Alohci
    Alohci over 10 years
    Note that "shouldn't (or more correctly, 'mustn't') have any content", is not "can't have any content". And if you do add content to a non-replaced void element via JavaScript, and the element is not hidden via display:none or similar, then that content will be rendered on the page. :before and :after pseudo-elements are just being consistent with that.
  • Jukka K. Korpela
    Jukka K. Korpela over 10 years
    The logic of the answer is not correct, as you can see e.g. from appendix D of the CSS 2.1 spec: it has a rule with the selector br:before. An element with EMPTY declared content still has content, it’s just empty, and you can append things to an empty string. There is no prohibition against input:after; it just has’t been implemented, or even defined well enough.
  • Robert Koritnik
    Robert Koritnik over 10 years
    @JukkaK.Korpela: But we could argue that empty content does not equal element's document tree content as it's not a sub-hierarchy of additional nodes.
  • Ale
    Ale over 10 years
    @deathlock @Robert I'll just leave it here: jsfiddle.net/52Y3j/1 (---maybe it's because hr was a block element some time ago, even without content--- disregard that, needs more research)
  • Spencer Williams
    Spencer Williams about 10 years
    Definitely some differences in implementation. Firefox will ignore br:after rules but it adheres to hr:after rules.
  • Rowan
    Rowan almost 10 years
    The next answer is way better.. Gives actual reason rather than talking about IE 7 (who cares) and jQuery (bad idea)
  • Radley Sustaire
    Radley Sustaire almost 10 years
    ":before and :after render inside a container" The :before and :after pseudo elements come "before and after the content". Not "at the beginning or end of" the container. The spec does not mention a container. With tags like p and h1, the content is within the tag, so before/after appear inside as well. With elements like input and hr, :before and :after would still appear before or after the content, but there is no container involved (especially for input). input:checked:before is widely used to indicate checkboxes being checked via css.
  • BoltClock
    BoltClock almost 10 years
    @RadGH: Reasonable nitpick in the first part of your comment, but 1) input and hr are void elements by definition and there cannot possibly have content 2) I'm pretty sure the :before pseudo-element has nothing to do with your last statement.
  • Radley Sustaire
    Radley Sustaire almost 10 years
    @BoltClock Maybe by the "void" definition it makes more sense, but is still questionable as these elements do create "something", even if not traditional "content". I think the specs need to clear that up instead of debating it, though. Regarding input:checked:before, I've seen this used in a variety of places (including WordPress' core) to style a checkbox. You style the input as the "box", and the :before element as the "check". It's used often enough that it must be reliable, even if inputs are a void element.
  • Blazemonger
    Blazemonger over 9 years
    +1 -- This solution works well if you're using a plugin or framework that automatically adds validation classes to the element itself, but not to the parent label.
  • Blazemonger
    Blazemonger over 9 years
    This is a comment, not an answer -- a rather long comment, but a comment nonetheless.
  • Jukka K. Korpela
    Jukka K. Korpela over 9 years
    @Blazemonger, it isn’t quite clear what was the question, but in any case, this answer addresses the same issue as the accepted answer, but in a more correct way. It’s not impossible to use generated content for input elements, just unspecified and browser-depending.
  • henry
    henry over 9 years
    Nice! Note that the placeholder pseudo element has limited property support: color, background, word-spacing, letter-spacing, text-decoration, vertical-align, text-transform, line-height, text-indent, opacity. See css-tricks.com/almanac/selectors/p/placeholder
  • Victor Ivens
    Victor Ivens about 9 years
    Nice trick, but you could make a div stylized to "continue" the input. See this fiddle jsfiddle.net/ose4r8uj/31 But you could also do it easier using bootstrap: getbootstrap.com/css/#forms-control-validation look for the "With optional icons" part. Even though, this has nothing to do with the original question.
  • jordanb
    jordanb over 8 years
    FYI no good for :focus, :hover, etc. of the input because you can't target the parent element
  • Davi Lima
    Davi Lima about 8 years
    Thanks for the hint. Just remember that everything inside the pseudo-element will disappear when the input box is filled in by user. That's an UX problem if all you wanted, like me, was displaying a glyphicon-search without touching markup.
  • kleinfreund
    kleinfreund about 7 years
    @RadleySustaire input:checked::before does not work reliably across browsers. Try this demo in Firefox: jsfiddle.net/bq1knxgb. There is no pseudo-element in the DOM.
  • Andrea_86
    Andrea_86 almost 7 years
    Not properly the same thing. $().after() append some context after an element, but i think that with :after and :befor he want to insert insede the element something before and something after
  • krassowski
    krassowski almost 7 years
    It allows to add hover actions, like: input:hover+span:after{color: blue}. Upvote.
  • Admin
    Admin over 6 years
    "In other words it's impossible with pure CSS." Not 100% right, @Alex. See my solution below.
  • Admin
    Admin over 6 years
    Plus, it's a bad pratice to add some text as-is in the DOM. You should wrap it in a span element.
  • BoltClock
    BoltClock over 6 years
    @Radley Sustaire: css-content-3 now states that replaced elements do not have ::before or ::after pseudos, but doesn't say whether form elements count as replaced elements (and I remember a recent conversation pointing out that the HTML spec says that they actually don't, which blows my mind). Anyone that uses it - or worse, relies on it - must not test on, or support, any other browser than Chrome. Which isn't a surprise, of course.
  • Radley Sustaire
    Radley Sustaire over 6 years
    @BoltClock Reading this years later I realize I must have been high or something - of course input:checked:before is not widely used but rather an accompanying label with :before is. I had provided incorrect information and appeared to believe it at the time. I wouldn't dare use a pseudo element on a checkbox now.
  • Oliver Joseph Ash
    Oliver Joseph Ash over 6 years
    Some context on why this no longer works: bugs.chromium.org/p/chromium/issues/detail?id=582301
  • ANeves
    ANeves about 5 years
    @dallin you can position a search icon in an input box, as a background-image.
  • kcpr
    kcpr about 5 years
    @ANeves, it worked in Chromium for me, but not in Firefox.
  • jorgefpastor
    jorgefpastor almost 5 years
    Why does this answer have so few upvotes? I think theoretical knowledge is important, but this solves the problem.
  • Jester
    Jester almost 5 years
    Nice option to go with in order to solve the problem.
  • Chris
    Chris almost 5 years
    I might not understand what you mean but if I do, pseudo elements work on hr? jsfiddle.net/demetriad/o49yn5hq
  • Manngo
    Manngo almost 5 years
    @Chris That comes as a surprise to me, and on searching, to some others. I think that’s a quirk. hr has always been ambiguous from the CSS point of view, though you see that more in discussing colour.
  • Mr Lister
    Mr Lister almost 5 years
    HTML 4 actually introduced the <button> element.
  • Rauli Rajande
    Rauli Rajande almost 4 years
    There still can be ::placeholder pseudo element inside the input
  • edddd
    edddd over 3 years
    @kleinfreund Still doesn't work with firefox in 2020. Weird that there's an MDN doc specifically recommending it developer.mozilla.org/en-US/docs/Learn/Forms/…
  • leonardseymore
    leonardseymore over 2 years
    This is really brilliant, nice job!
  • Esger
    Esger almost 2 years
    Yes, type="submit" works as well.