CodeinWP CodeinWP

Detecting Specific Text Input with HTML and CSS

Recently I came across a CodePen demo by a developer/engineer named Jane that was Tweeted out by Šime Vidas. The demo has a neat collection of HTML and CSS tricks rolled into one that I thought was worth examining in detail.

The page displays a secret message based on specific text input. Ok, that’s no big deal, right? Well this is done using pure HTML and CSS – no JavaScript. I’ve seen stuff like this before, but I thought it would be cool to break down exactly how this works. There are a few notable things happening in the code so I’ll break down each of the parts. Here’s the demo:

See the Pen
Add secret website button codes with vanilla CSS (NO JS!)
by Jane 💜 (@propjockey)
on CodePen.

Just make sure, as the instruction says, that your cursor is focused inside the CodePen preview window.

Using HTML’s accesskey

As the revealed secret message points out, the demo is using HTML’s accesskey attribute. That’s a bit of a blast from the past for some of us. It’s an old feature that:

provides a hint for generating a keyboard shortcut for the current element.

This means the user can trigger focus on the targeted element using a browser- or platform-specific key combination along with the specified accesskey value (which can be any “printable” character generated by the keyboard).

You can set up an accesskey value like this:

<input accesskey="c">

MDN’s article on accesskey has a handy chart showing how the accesskey can be triggered by the user on different browsers and platforms. The most likely combination is either ALT-KEY (Windows) or CTRL-ALT-KEY (Mac) – though there are a lot of variations depending on the browser.

In Jane’s demo, the input is visually hidden but still accessible. I’ll get to more on accesskey in a moment but let’s also look at the other interesting things in the demo.

Using the pattern Attribute

The other thing that makes this trick work is the use of the pattern attribute on the hidden text field. Strangely, MDN’s article doesn’t display the browser compatibility for pattern, but the attribute seems to be safe to use. If I recall correctly, this feature was added a little later than other HTML5 forms features.

This attribute accepts a regular expression that should be matched for the form field to validate. It can be used on text, tel, email, url, password, and search inputs.

In this instance, the demo isn’t using any special regex characters to do anything fancy – it’s just straight text that’s matched.

<input accesskey="c" pattern="wow!">

But there’s no form submission going on here, so how is this form field being “validated”?

The :valid and :placeholder-shown Pseudo-classes

In order to check if the form field is valid, the demo makes use of the :valid CSS pseudo-class. So you can do something like the following to apply different styles to a form field that’s valid but hasn’t been submitted yet:

:valid {
  border: solid 1px green;
}

This will instantly place a green border on any valid form field, no need for form submission. There’s also a pseudo-class of :invalid which does the opposite. Both have good browser support, so don’t be afraid to use these.

The demo also uses the :placeholder-shown pseudo-class. This pseudo-class targets elements that are using the HTML placeholder attribute and whose placeholder value is visible (i.e. the user hasn’t inserted text to remove the placeholder value).

:placeholder-shown {
  background: white;
}

This feature isn’t important to the overall technique, but it’s part of the big selector that I’ll discuss next.

The Big Fancy CSS Selector

Once we understand those two pseudo-classes, then we can begin to grasp the big selector used in the demo:

.secret-code:not(:placeholder-shown):valid ~ * {
  --secret_code: ;
}

In addition to the :valid and :placeholder-shown pseudo-classes, the selector is using the more common :not() pseudo-class along with a sibling selector and a universal selector. That’s quite a bit to digest in a single CSS selector, but here’s what it means in plain English:

  • Target all sibling elements
  • Of every element with a class name of .secret-code
  • That has no placeholder text showing
  • That’s valid

And once we grasp that selector, then we can move on to the main CSS trick used to toggle the secret message on and off.

The --var() Space-toggle Hack

The demo is using a trick referred to as the space-toggle hack (or var-toggle hack), which Lea Verou nicely explained a year ago and apparently was first used/discovered by Ana Tudor. This trick uses CSS custom properties (i.e. CSS Variables). In fact, Jane has used it in multiple projects including CSS Mine Sweeper and a library called Augmented UI.

This technique is a way to easily toggle a set of CSS property/value pairs on a single element using a single property value.

Take note of the inline styles present on the div element in the demo:

<div style="--wow: var(--secret_code) green; color: var(--wow, black);">

The odd thing here, and the thing that makes the space-toggle hack work, is the value for the --wow custom property. Before the selector criteria is met, the value of this custom property is invalid. This is because the --secret_code variable has no value set (yet). The value of green that appears after the invalid custom property will take effect once the space character is put in place (hence the name “space-toggle hack”).

This essentially means --wow: var(--secret_code) green; will compute to --wow: green; (because the space is just extra white space, which is fine inside a CSS value).

To make it more clear, in plain English the inline style reads like this:

  • Define the --wow variable with a non-existent custom property followed by a space and the color green
  • Set the color property to whatever the --wow variable is set to (currently invalid), with a fallback of black
  • Since --wow is currently invalid, use its fallback

This is why the color of the text starts out black when you first load the page.

The key to the toggle, then, is to add a space character as a value for --secret_code. This makes the initial definition of --wow valid, so the fallback color of black isn’t used. Once the space character is inserted, the logic is like this:

  • Define the --wow variable with a space character, followed by another space and the color green
  • Set the color property to whatever the --wow variable is set to (currently a valid space), with a fallback of black
  • Since --wow is currently valid, and doesn’t break the value of green, the color is computed to green

The same logic applies to the hidden span element that shows the secret message:

<span style="--wow: var(--secret_code) block; display: var(--wow, none);">

Again, the value of “block” won’t take effect until the selector criteria is met, thus making var(--secret_code) valid (and, by extension, --wow is valid).

One of the things that first tripped me up about the space-toggle hack is the value that follows the invalid variable. In this case it was green. To me this looked like a fallback value, so the logic didn’t make sense at first glance. But this isn’t a fallback value; it’s a value that gets toggled “on” when the variable next to it gets validated by the space character passed in from the selector’s variable definition.

And one final thing about the space-toggle hack: It’s really not recommended in a lot of cases and will cause problems with some CSS minifiers. A minifier is usually going to delete unwanted space characters like the one set as the value in this hack. I tested it on a few online minifiers and it does indeed cause problems for some, but not all. So be aware of that if you choose to use this technique.

Final Warning About Using accesskey

As mentioned, this trick uses the accesskey attribute, which seems like a useful feature to take advantage of. As the original Tweet by Šime mentions, WebAIM provides a warning when discussing this subject:

Despite good intentions and because of varied and insufficient browser implementations, accesskey very often does not provide a viable solution for keyboard shortcuts on the web.

They go on to offer a whole slew of reasons why using accesskey is problematic and conclude with:

Due to numerous problems with implementation, accesskey is typically best avoided. If used, they must be implemented carefully. The bottom line: some users will benefit and some will not, and some may even be disadvantaged.

While the accesskey part of this trick is the primary reason it works, I hope the rest of it (which is more likely to be used) was somewhat educational to those of you who weren’t as familiar with it all.

Web Tools Weekly

Leave a Reply

Comment Rules: Please use a real name or alias. Keywords are not allowed in the "name" field and deep URLs are not allowed in the "Website" field. If you use keywords or deep URLs, your comment or URL will be removed. No foul language, please. Thank you for cooperating.

Markdown in use! Use `backticks` for inline code snippets and triple backticks at start and end for code blocks. You can also indent a code block four spaces. And no need to escape HTML, just type it correctly but make sure it's inside code delimeters (backticks or triple backticks).