Introduction

UPDATE 2016: this appears to have even less support than before, and it's not recommended to be used on a production site. Use a helper JS library instead.

(check out the Demo)

A while back I had a bit of a field day messing around with input type=”range”, trying to replicate the “unlock slider” on iOS using CSS, targeting special WebKit-only CSS pseudoelements such as webkit-slider-thumb.

Well, now I’m at it again, this time with a much simpler use case, trying to implement a custom “clear” button on search field inputs (note that this only works on input type=”search”):

Custom webkit-search-cancel-button

Details about the implementation

It turns out this is relatively easy to do, and is somewhat supported, at least in the latest Chrome and Safari 6. Note that it does work on iOS6, but not on iOS5, but the positioning is slightly different from the other implementations. No idea about Android, so I’ll leave that for someone else to find out. :)

So how do we do it? First, we need the special WebKit CSS pseudoselector (-webkit-search-cancel-button), and secondly, we need to use that to wipe out the default WebKit styling (with -webkit-appearance: none;):

1
2
3
::-webkit-search-cancel-button {   // select all "X" buttons in search inputs
    -webkit-appearance: none;      // hide the default "X" button
}

You would think that the next step might be adding our own custom background-image to this element, but unfortunately it won’t work that easily (of course).

What we need now is a little bit of trickery, using an :after pseudoclass on the pseduoclass (!?). The result is a bit of “pseudoclass Inception”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
::-webkit-search-cancel-button {   /* select all "X" buttons in search inputs */
    -webkit-appearance: none;      /* hide the default "X" button */
}

::-webkit-search-cancel-button:after {  /* generate content after all "X" buttons */
    content: '';    /* required for :after content to show */
    display: block;

    /*
     * Setup dimensions for the custom icon.  Note that these dimensions seem to
     * affect positioning.
     */
    width: 14px;
    height: 10px;

    /*
     * Base64 encoded custom "X" icon
     * Natively 30x30, but downscaled for highres screens
     */
    background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAn0lEQVR42u3UMQrDMBBEUZ9WfQqDmm22EaTyjRMHAlM5K+Y7lb0wnUZPIKHlnutOa+25Z4D++MRBX98MD1V/trSppLKHqj9TTBWKcoUqffbUcbBBEhTjBOV4ja4l4OIAZThEOV6jHO8ARXD+gPPvKMABinGOrnu6gTNUawrcQKNCAQ7QeTxORzle3+sDfjJpPCqhJh7GixZq4rHcc9l5A9qZ+WeBhgEuAAAAAElFTkSuQmCC);

    /* setup all the background tweaks for our custom icon */
    background-repeat: no-repeat;

    /* icon size */
    background-size: 10px;

    /* note: this positioning will need to be tweaked for iOS */
    background-position: top left;
}

So it turns out you can still whatever you like in there really, even text content (see the last text input in the demo). You may even need to tweak the positioning a bit, in which case you can learn from the same example (you will need to set position:relative on the cancel button itself to anchor the position:absolute :after content - check out the code).

Final notes

Note that this is just an experiment, not a robust use case that I’m recommending as a cross-browser solution (obviously, since it’s WebKit-only).

In the case of wanting to implement something similar cross-browser, I recommend absolutely-positioning a button element over an input element, then adding the appropriate right-padding to the input as necessary, then hooking up the “clear all text” behavior with the help of JavaScript.

Video

Here’s a video if you’re not in the mood to read (view in HD so you can read the text!):