Bring Focus to the First Form Field with an Error :: Aaron Gustafson
A handy little script from Aaron to improve the form validation experience.
A handy little script from Aaron to improve the form validation experience.
The opening paragraphs of this article should be a mantra recited by every web developer before they begin their working day:
Things on the web can break — the odds are stacked against us. Lots can go wrong: a network request fails, a third-party library breaks, a JavaScript feature is unsupported (assuming JavaScript is even available), a CDN goes down, a user behaves unexpectedly (they double-click a submit button), the list goes on.
Fortunately, we as engineers can avoid, or at least mitigate the impact of breakages in the web apps we build. This however requires a conscious effort and mindset shift towards thinking about unhappy scenarios just as much as happy ones.
I love, love, love the emphasis on reducing assumptions:
Taking a more defensive approach when writing code helps reduce programmer errors arising from making assumptions. Pessimism over optimism favours resilience.
Hell, yeah!
Accepting the fragility of the web is a necessary step towards building resilient systems. A more reliable user experience is synonymous with happy customers. Being equipped for the worst (proactive) is better than putting out fires (reactive) from a business, customer, and developer standpoint (less bugs!).
I think I’ve found some more strange service worker behaviour in Chrome.
It all started when I was checking out the very nice new redesign of WebPageTest. I figured while I was there, I’d run some of my sites through it. I passed in a URL from The Session. When the test finished, I noticed that the “screenshot” tab said that something was being logged to the console. That’s odd! And the file doing the logging was the service worker script.
I fired up Chrome (which isn’t my usual browser), and started navigating around The Session with dev tools open to see what appeared in the console. Sure enough, there was a failed fetch
attempt being logged. The only time my service worker script logs anything is in the catch
clause of fetching pages from the network. So Chrome was trying to fetch a web page, failing, and logging this error:
The service worker navigation preload request failed with a network error.
But all my pages were loading just fine. So where was the error coming from?
After a lot of spelunking and debugging, I think I’ve figured out what’s happening…
First of all, I’m making use of navigation preloads in my service worker. That’s all fine.
Secondly, the website is a progressive web app. It has a manifest file that specifies some metadata, including start_url
. If someone adds the site to their home screen, this is the URL that will open.
Thirdly, Google recently announced that they’re tightening up the criteria for displaying install prompts for progressive web apps. If there’s no network connection, the site still needs to return a 200 OK
response: either a cached copy of the URL or a custom offline page.
So here’s what I think is happening. When I navigate to a page on the site in Chrome, the service worker handles the navigation just fine. It also parses the manifest file I’ve linked to and checks to see if that start URL would load if there were no network connection. And that’s when the error gets logged.
I only noticed this behaviour because I had specified a query string on my start URL in the manifest file. Instead of a start_url
value of /
, I’ve set a start_url
value of /?homescreen
. And when the error shows up in the console, the URL being fetched is /?homescreen
.
Crucially, I’m not seeing a warning in the console saying “Site cannot be installed: Page does not work offline.” So I think this is all fine. If I were actually offline, there would indeed be an error logged to the console and that start_url
request would respond with my custom offline page. It’s just a bit confusing that the error is being logged when I’m online.
I thought I’d share this just in case anyone else is logging errors to the console in the catch
clause of fetches and is seeing an error even when everything appears to be working fine. I think there’s nothing to worry about.
Update: Jake confirmed my diagnosis and agreed that the error is a bit confusing. The good news is that it’s changing. In Chrome Canary the error message has already been updated to:
DOMException: The service worker navigation preload request failed due to a network error. This may have been an actual network error, or caused by the browser simulating offline to see if the page works offline: see https://w3c.github.io/manifest/#installability-signals
Much better!
Another five pieces of sweet, sweet low-hanging fruit:
- Always label your inputs.
- Highlight input element on focus.
- Break long forms into smaller sections.
- Provide error messages.
- Avoid horizontal layout forms unless necessary.
This is a great walkthough of making a common form pattern accessible. No complex code here: some HTML is all that’s needed.
Bayesian analysis vs. statistical significance, clearly explained.
This might just be the most nerdily specific book I’ve read and enjoyed. Even if you’re not planning to build a web browser any time soon, it’s kind of fascinating to see how HTML is parsed—and how much of an achievement the HTML spec is, for specifying consistent error-handling, if nothing else.
The last few chapters are still in progress, but you can read the whole thing online or buy an ePub version.
Whenever I create a fetch
event inside a service worker, my code roughly follows the same pattern. There’s a then
clause which gets executed if the fetch is successful, and a catch
clause in case anything goes wrong:
fetch( request)
.then( fetchResponse => {
// Yay! It worked.
})
.catch( fetchError => {
// Boo! It failed.
});
In my book—Going Offline—I’m at pains to point out that those arguments being passed into each clause are yours to name. In this example I’ve called them fetchResponse
and fetchError
but you can call them anything you want.
I always do something with the fetchResponse
inside the then
clause—either I want to return
the response or put it in a cache.
But I rarely do anything with fetchError
. Because of that, I’ve sometimes made the mistake of leaving it out completely:
fetch( request)
.then( fetchResponse => {
// Yay! It worked.
})
.catch( () => {
// Boo! It failed.
});
Don’t do that. I think there’s some talk of making the error argument optional, but for now, some browsers will get upset if it’s not there.
So always include that argument, whether you call it fetchError
or anything else. And seeing as it’s an error, this might be a legitimate case for outputing it to the browser’s console, even in production code.
And yes, you can output to the console from a service worker. Even though a service worker can’t access anything relating to the document
object, you can still make use of window.console
, known to its friends as console
for short.
My muscle memory when it comes to sending something to the console is to use console.log
:
fetch( request)
.then( fetchResponse => {
return fetchResponse;
})
.catch( fetchError => {
console.log(fetchError);
});
But in this case, the console.error
method is more appropriate:
fetch( request)
.then( fetchResponse => {
return fetchResponse;
})
.catch( fetchError => {
console.error(fetchError);
});
Now when there’s a connectivity problem, anyone with a console window open will see the error displayed bold and red.
If that seems a bit strident to you, there’s always console.warn
which will still make the output stand out, but without being quite so alarmist:
fetch( request)
.then( fetchResponse => {
return fetchResponse;
})
.catch( fetchError => {
console.warn(fetchError);
});
That said, in this case, console.error
feels like the right choice. After all, it is technically an error.
Rebuttals to the most oft-asked requests for browsers to change the way they handle CSS.
Dave uses just a smidgen of JavaScript to whip HTML5’s native form validation into shape.
Instead of being prescriptive about error messaging, we use what the browser natively gives us.
I saw Christian speak on this topic at Smashing Conference in Barcelona. Here, he takes a long hard look at some of the little things that sites get wrong when doing validating forms on the fly. It’s all good sensible stuff, although it sounds a bit medical when he takes about “Premature Inline Validation.”
This is really, really clever. You can’t use generated content (:before
and :after
) on replaced content. The img
element is replaced content …but only when the image actually loads. So if the image fails to load, you can apply specific fallback styles (using :before
and :after
).
This is my go-to method for adding validation messages to forms—I think I first heard about it from Derek—so it’s nice to see it corroborated by Steve:
Add the error message as a child of the label element associated with an input.
Web developers overwhelmingly rejected the draconian error-handing of XML …and yet today, web developers are embracing that very same error-handling model by rendering everything with JavaScript.
I don’t think it’s the way of the web to have your site fail and show a blank screen because some third-party dependency doesn’t load, JavaScript is turned off or because your developer left a trailing comma in a JavaScript object and didn’t test in Internet Explorer.
This is possibly the most horrifying piece of JavaScript ever written. The license is good too.