The idea is for these text fields is not original, but it made for a nice exercise and research project. I avoided looking up other implementations.
I worked out three methods, all of which change the style on focus and when the text field is not blank. Having the change in style for a non-blank field was the tricky part. Ideally we could use the :blank
CSS selector, if only it was actually developed and supported. That leaves us with several options. Two methods use only CSS by using the placeholder
or required
attributes, but these are not ideal in practicality, browser support or accessibility. The third uses a minimal amount of JavaScript, which works best but obviously requires JavaScript to be enabled.
After the examples we'll go over the HTML, CSS, and Javascript used in the following segments:
- The basics, the HTML and CSS used for all 3 methods
- Method 1, using the placeholder attribute
- Method 2, using the required attribute
- Method 3, using JavaScript
Links to documentation: In the HTML examples the opening tags link to the relevant MDN web docs page for those elements, while in the CSS examples the property names, and pseudo classes and elements link to their MDN web docs pages.
The examples
The basics
The HTML
The aim was to keep the HTML as simple and accessible as possible. What I ended up with was simply an input
element wrapped in a label
, with a span
element for the label text which we'll position using CSS.
The CSS
The CSS is where the magic happens. We have our label
, input
, and span
to provide basic style and (very important in this case) position.
First we define our label style. The height defines the height of our entire element, if we change this, we will need to change the height and / or padding of our input
element, and the position of our span
element. A cursor is defined to ensure the expected cursor for an input
element is shown wherever we hover on the element.
We are going to fill out our entire label
element with our input
using a combination of height and padding. The width we apply here determines the width of our entire element. Lastly we provide a bottom border and apply a transition value, to make style changes appear more smoothly.
With our input
element filling out our label
, we need to position our helpful span
element. We move its relative position up, and make the initial text size a bit larger for when the input
value is still empty. To make our transition smooth and consistent, we give it the same value as we gave our input
element.
To make it clear we are hovering over the input
element we'll make the background a tad lighter. We'll keep this lighter background when it has focus too.
We want to move our label text out of the way when we start typing, to do that we reposition our span
element and resize the text when the input
has focus. As an extra focus indicator we'll also change the text color.
Lastly we define a text and border color on our input
to indicate focus. I disabled the standard outline, you should only do that when you provide adequate alternative focus indicators.
With this we get this text field that's pretty nice already, but after we type something things get ugly when we lose focus (isn't that a universal truth?).
Losing focus with style
Method one: the placeholder attribute
For this method we use the placeholder
attribute with a space, because we don't actually want a visible placeholder text. When an input
isn't blank, any placeholder text it has is hidden from view.
To directly target our span
when the input
isn't showing the placeholder, we use a combination of the :not()
and :placeholder-shown
selectors in our CSS. Here we move the span
up, and resize the text.
This method is not recommended because screen readers may announce the value of the placeholder
attribute as "blank", which might lead to confusion. Aside from that, placeholders in general have accessibility considerations as the information they convey disappears when you start typing in the field. It also appears that the CSS selector is not supported in IE11 and Edge at the time of writing.
Method two: the required attribute
For this method we use the required attribute on the input
element. This will make it so we can apply a style using the :valid
selector in CSS. When no additional requirements are given, a required field will be deemed valid as long as it is not empty.
To directly target our span
when the input
isn't blank, we use the following bit of CSS.
This method is not recommended unless every field in your form is required. In that case you should make sure this is communicated to the user in a clear way, and you'll want to provide adequate error messages.
Method three: let's get some help from JavaScript
Now we know just CSS isn't going to work for us, let's see how we can get this working with a bit of JavaScript. What we are going to do is make a function which we call on the onkeyup
event like this.
Our function is going to check if the value is empty. If it's not empty we add a class to the text field, if it is empty we simply remove the class.
When using this bit of JavaScript to toggle the class, we can use the class selector in our CSS like this.
With this method we finally achieve the desired result, without the drawbacks of the other methods. With a choice between these methods, I would recommend the JavaScript solution.
Notes on accessibility
While this element is accessible in a technical and semantical sense using methods 2 or 3, you should always consider the text sizes and color contrast, and provide adequate label text. If a field is required, be sure to signal this clearly to the user with explanation of any requirements.