Integrate Custom Elements into Forms with ElementInternals

Over at CSS-Tricks, Caleb Williams digs into ElementInternals

The ElementInternals standard is a very exciting set of features with a very unassuming name. Among the features internals adds are the ability to participate in forms and an API around accessibility controls.

As you can see in the demo below his <rad-input> does exactly that.

See the Pen
Rad input with validation
by Caleb Williams (@calebdwilliams)
on CodePen.

Creating Custom Form Controls with ElementInternals

🤨 New to Web Components? John Rhea recently wrote two nice articles for CSS-Tricks covering the basics:

Form Validation: You want :not(:focus):invalid, not :invalid

Update 2021-01-28: In case your form controls have the required attribute set, you’ll even want to use the more extensive :not(:focus):not(:placeholder-shown):invalid selector.

See the update at the end of this post for more info on this.

We’ve all been in this situation, where the built-in form validation of the browser starts complaining while you’re still entering data into the form:

Highly annoying, but thankfully there’s an easy way to fix this.

~

# The problem

The problem is caused by a piece of CSS similar to this snippet:

.error-message {
    display: none;
}

input:invalid {
  border-color: var(--color-invalid);
}

input:invalid ~ .error-message {
  display: block; 
}

input:valid {
  border-color: var(--color-valid);
}

When entering an e-mail address — as Ryan is doing above — this is extremely annoying as your e-mail address is only valid when you’re done entering it. Try it in the demo below.

See the Pen
Form Validation on Blur (1/4)
by Bramus (@bramus)
on CodePen.

Ugh! 🤬

💁‍♂️ For a slight moment you’ll notice that an e-mail address in the form of bramus@bram (e.g. without a .tld suffix) is also considered valid. As per RFC 822 the user@hostname format — used mainly in local networks — indeed is allowed.

~

# Making things better

It would be nice to only perform the validation when the field is not being edited anymore. In CSS we don’t have a blur event, but what we do have is a pseudo-class selector to indicate whether an input has the focus: :focus. Combine that with :not() and we have a way to target the “not being focussed” state, which also indicates that the field is not being edited.

Putting it all together, our CSS becomes this:

.error-message {
    display: none;
}

input:not(:focus):invalid {
  border-color: var(--color-invalid);
}

input:not(:focus):invalid ~ .error-message {
  display: block; 
}

input:not(:focus):valid {
  border-color: var(--color-valid);
}

This way the validations only happen when you’re blurred out of the form.

See the Pen
Form Validation on Blur (2/4)
by Bramus (@bramus)
on CodePen.

Ah, that’s better! 😊

~

# Making things even more better

In the demo above you’ll see one small side-effect though: the border is green by default, even though we didn’t enter any value. This is not exactly what we want Ideally we only want to validate in case the field is both not focussed and not empty.

In CSS we can’t use :empty for this though, as :empty targets elements that have no children/innerHTML content. What we can do however is abuse the :placeholder-shown pseudo-class.

  • If there’s no text entered, the placeholder is shown
  • If there is text entered, the placeholder is not shown

With this in mind, our code now becomes this:

.error-message {
    display: none;
}

input:not(:focus):invalid {
  border-color: var(--color-invalid);
}

input:not(:focus):invalid ~ .error-message {
  display: block; 
}

input:not(:focus):not(:placeholder-shown):valid {
  border-color: var(--color-valid);
}

⚠️ Do note that this requires a value for the input‘s placeholder.

<input type="email" placeholder="you​@​example​.​org" />

If you don’t want any placeholder to show, set its value to   (space)

Here’s an adjusted demo:

See the Pen
Form Validation on Blur (3/4)
by Bramus (@bramus)
on CodePen.

Yes, exactly what we want! 🤩

Note: In the future we will be able to use the :user-invalid pseudo class for exactly this use-case.

The :user-invalid pseudo-class represents an element with incorrect input, but only after the user has significantly interacted with it.

This feature is still in the works and not supported yet. Firefox supports it using the non-standard ::-moz-ui-invalid name. Thanks for the tip, Schepp!

~

# Update 2021-01-28: Playing nice with required

As reader Corey pointed out in the comments below the code above does not play nice with the required attribute. When the attribute is added, the error message will be shown when the form loads.

To work around this we also need to include the :not(:placeholder-shown) pseudo-class in our :invalid selectors.

.error-message {
    display: none;
}

input:not(:focus):not(:placeholder-shown):invalid {
  border-color: var(--color-invalid);
}

input:not(:focus):not(:placeholder-shown):invalid ~ .error-message {
  display: block; 
}

input:not(:focus):not(:placeholder-shown):valid {
  border-color: var(--color-valid);
}

Putting it all together, here’s our final demo:

See the Pen
Form Validation on Blur (4/4)
by Bramus (@bramus)
on CodePen.

Phew! 😅

~

🔥 Like what you see? Want to stay in the loop? Here's how:

Note: The title of this post is definitely a reference to this post on CSS-Tricks and this post by Kilian.

Accept several email addresses in a form with the multiple attribute

A popular tweet of mine that’s been doing rounds again (thanks to an RT by Stefan, whom you should definitely follow) is this little tip:

By setting the multiple attribute on an input[type="email"] you can have it accept multiple entries. Each entry is separated by a comma and is validated individually.

Here’s a little demo video of how that works:

💁‍♂️ For a slight moment there you can see that bramus@bram is considered valid. As per RFC 822 the user@hostname format — used mainly in local networks — indeed is allowed.

~

However, it was pointed out to me that on iOS this isn’t usable by default:

On iOS, the “email keyboard” looks like this, with no comma to be found (not even when switching to numbers/symbols):

To work around this limitation you can manually override the input to use the regular keyboard by setting the inputmode attribute to text.

That way we still have the built-in browser validation rules (triggered by [type="email"]) and a means to type in a comma (triggered by [inputmode="text"]). Double win!

💁‍♂️ Sidenote: With this inputmode attribute you can create better number inputs.

~

Combining what we know, here’s a full demo for you to play with:

See the Pen
Accepting multiple e-mail addresses in one input
by Bramus (@bramus)
on CodePen.

~

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Litepicker Date Range Picker

I like that the daterange needs to be entered in one single input, and that the rendered datepicker is used as a progressive enhancement on top.

Installation per NPM:

npm i litepicker

At its core, usage is really simple:

import Litepicker from 'litepicker';

const picker = new Litepicker({ element: document.getElementById('litepicker') });

Highly configurable too!

Litepicker — Date range picker – lightweight, no dependencies →

“Yes or No?” — One Checkbox vs Two Radio Buttons

Great research by Sara Soueidan:

If you have a question with a binary Yes/No answer, is it better to use one checkbox or two radio buttons?

As per usual: It Depends™. The consensus however seems to be that requiring an explicit “No” is the determining factor to avoid the simple checkbox.

Over at CSS-Tricks Chris Coyier has collected several options how to implement this, in one handy pen:

See the Pen Ways to ask Yes or No by Chris Coyier (@chriscoyier) on CodePen.

Do note that not all of those listed options are as usable as the others. As Sara says:

[A]s with all user interfaces, nothing beats the input you can get from user testing and research.

“Yes or No?” — One Checkbox vs Two Radio Buttons →

Customise the caret color with the CSS caret-color property

Thanks to this tweet by Álvaro Trigo I found out that you can change the color of the caret — that little blinking | in text inputs — using the caret-color CSS property:

Example:

input {
  caret-color: red;
}

💁‍♂️ Do note that the caret-color defaults to currentColor, so you don’t need to manually match the color set on an element.

~

Browser support is really great:

Data on support for the css-caret-color feature across the major browsers from caniuse.com

💡 Shown above is a live CanIUse.com table, showing an always up-to-date support table. By the time you are reading this browser support might have become better.

~

Wondering if there were more caret-* properties this turned out to be not the case. A pity though, as I can think of cases where I would like to set the caret-height and caret-thickness, such as emulating the cursor of a terminal:

~

As a fun little experiment Tim Carambat created a Pen that changes the caret color from green to yellow to red as you near the maxlength of the <textarea> you’re typing in.

See the Pen
Color Changing Cursor in TextArea
by Timothy Carambat (@rambat1010)
on CodePen.

Usability-wise this isn’t that great, but it’s fun nonetheless 🙂

HTML Forms: How (and Why) to Prevent Double Form Submissions

When double clicking a submit button your form will be sent twice. Using JavaScript you can prevent this from happening, but wouldn’t it be nice if this behavior could be tweaked by use of an attribute on the <form>? If you think so, feel free to give this issue a thumbs up.

Today Sebastian wondered:

I quickly chimed in saying that I do tend to lock up forms when submitting them. Let me explain why …

~

I started locking up submitted forms as users of the apps I’m building reported that sometimes the actions they had taken — such as adding an entry — were performed twice. I took me some time to figure out what exactly was going on, but eventually I found out this was because they were double clicking the submit button of the forms. As they double clicked the button, the form got sent over twice. By locking up forms after their first submission, all successive submissions — such as those triggered by that second click of a double click — are ignored.

~

To prevent these extra form submissions from being made I don’t hijack the form with Ajax nor do I perform any other complicated things. I let the inner workings of the web and forms in the browser be: when pressing the submit button the browser will still collect all form data, build a new HTTP request, and execute that request.

What I simply do is extend the form’s capabilities by adding a flag — by means of a CSS class — onto the form to indicate whether it’s being submitted or not. I can then use this flag’s presence to deny any successive submissions, and also hook some CSS styles on. — Progressive Enhancement, Yay! 🎉

The code looks as follows:

 // Prevent Double Submits
document.querySelectorAll('form').forEach(form => {
	form.addEventListener('submit', (e) => {
		// Prevent if already submitting
		if (form.classList.contains('is-submitting')) {
			e.preventDefault();
		}
		
		// Add class to hook our visual indicator on
		form.classList.add('is-submitting');
	});
});

💡 Although the problem initially was a double click problem, we don’t listen for any clicks on the submit button but listen for the form’s submit event. This way our code not only works when clicking any of the submit buttons, but also when pressing enter to submit.

With that .is-submitting class in place, we can then attach some extra CSS onto the form to give the user visual feedback. Here’s a few examples:

See the Pen
Prevent Form Double Submits
by Bramus (@bramus)
on CodePen.

See the Pen
Prevent Form Double Submits (Alternative version)
by Bramus (@bramus)
on CodePen.

Note that this solution might not cover 100% of all possible scenarios, as it doesn’t take failing networks and other things that might go wrong into account. However, as I’m relying on the basic mechanisms of the web I think I can also rely on the browser to show that typical “Confirm Form Resubmission” interstitial should a timeout occur. Additionally, if need be, one could always unlock the form after a fixed amount of time. That way the user will be able to re-submit it again.

~

Dealing with double form submissions isn’t a new issue at all. You’ll find quite some results when running a few queries through Google — something I only found out after stumbling over the issue myself.

Back in 2015 (!) Mattias Geniar also pondered about this, after being pulled into the subject from a sysadmin view. Now, when even sysadmins are talking about an HTML/UX issue you know there’s something going on. This made me wonder why browsers behaved like that and how we could solve it:

As a result I decided to open an issue at the WHATWG HTML Standard repo, suggesting for a way to fix this at spec level:

An attribute on <form> to tweak this behavior – instead of having to rely on JavaScript – would come in handy and form a nice addition to the spec.

I see two options to go forward:

  1. Browsers/the standard keeps the current behavior and allow multiple submits. Developers must opt-in to prevent multiple submissions using a preventmultiplesubmits attribute.
  2. Browsers/the standard adjust the current behavior to only submit forms once. Developers must opt-in to allow multiple submissions using a allowmultiplesubmits attribute.

Initial response on the issue was very low, and it looks like this isn’t that big of a priority.

Back then I was more in favor of the second solution, but now I’m quite undecided as changing the default behavior — which has been around for ages — is quite tricky.

~

Another way that this issue could be fixed is at the browser level: if they were to treat double clicks on form submit buttons as single clicks, then the double click problem — but not the double submit problem — could also be taken care of.

To then attach styles to forms being submitted a CSS Pseudo Class :submitting would come in handy. Come to think of it, this Pseudo Class would be a quite nice addition to CSS in itself, no matter whether this double click issue gets solved or not.

~

Winging back to the addition to the HTML spec I suggested: If you do think it could be something the HTML spec could benefit from, feel free to add a thumbs up to the issue to indicate that you want this, or add an extra comment to it if you have more input on the subject.

Did this help you out? Like what you see?
Thank me with a coffee.

I don't do this for profit but a small one-time donation would surely put a smile on my face. Thanks!

☕️ Buy me a Coffee (€3)

To stay in the loop you can follow @bramus or follow @bramusblog on Twitter.

Make <input type="number"> respond to arrow keys with modifier keys

By default <input type="number"> elements will increment/decrement by its step attribute value when pressing the up/down arrows. Kilian Valkhof provides us with some JavaScript to have these elements also respond to up/down keypresses while holding modifier keys.

When someone uses the arrow keys in the input field, we want the following to happen:

  • If they press up or down, we want to add or subtract 1
  • If they hold SHIFT and press up or down, we want to add or subtract 10
  • If they hold ALT and press up or down, we want to add or subtract 0.1
  • If they hold CTRL and press up or down, we want to add or subtract 100. On Mac, we want to use the CMD key for consistency.

Supercharging <input type="number">

💡 Did you know the DevTools in your browser also support these modifier keys? Try editing a numeric value and press up/down while holding SHIFT/ALT/CMD 😉

⚠️ In some cases you’ll most likely be better off by avoiding <input type="number">, and should use go for <input type="text" inputmode="numeric" pattern="[0-9]*"> instead`.

Checkboxland – Render anything as HTML checkboxes

Checkboxland is a JavaScript library for rendering anything as HTML checkboxes.

You can use it to display animations, text, and arbitrary data. It also supports plugins, so you can build more powerful APIs on top of it.

Heh. Can’t quite think of a reason when exactly to use this, but it’s fun nonetheless 😅

Checkboxland →

👾 This reminded me of Fullstack, a game built by Hakim El Hattab:

Limit the colors to choose from in <input type=”color”> with <datalist>

Christian Heilman:

The input type colour supports the list attribute, which allows you to define a preset list of options. The colours need to be defined as hexadecimal colours. They can be defined as values or text inside the option tags, but the values take precedence.

Pictured at the top of this post is how Chromium-browsers render the following snippet:

<input type="color" list="presets"></label>
<datalist id="presets">
  <option value="#cccccc">Grey</option>
  <option value="#ffffff">White</option>
  <option value="#6699cc">Blue</option>
</datalist>

In his article he continues with dynamically adjust the colors to choose from, based on the color palette of an uploaded image.

UPDATE 2020-04-27: Turns out it’s also possible to limit the options for datepickers and range sliders: datalist experiment. (via)

Limiting input type=”color” to a certain palette (from an image) →