HTML onerror: The Good, the Bad, and the Ugly

A Fist Full of Solutions

While doing my front-end work I’m very keen on using simple markup techniques to solve problems before relying on the likes of Javascript. Don’t get me wrong, I gargle MooTools and jQuery every morning to keep my web breath fresh like most developers, but I find it endlessly attractive when an elegant solution can be flossed out using only pure HTML and CSS.

Finding a solution is never a problem, but choosing a solution is often a challenge. Selecting one technique among the wealth of available methods that strikes a balance between the simplicity and elegance of pure HTML and CSS, the flexibility and mysticality of Javascript, and the raw power of PHP is often a feat in and of itself. When I can’t go with pure HTML and CSS, I do my best to at least heavily rely on their available features before turning to the usual Javascript frameworks for support.

The Good

I was recently working on a GUI that included user avatar pictures. While the platform itself did not require the user to have a photo, the interface design looked significantly better when there was a graphic present. For this reason I decided to use default avatar images. The idea was to apply the user’s provided image URL only if it was valid and alternatively resort to the default image if it wasn’t. I wanted to avoid doing any logic-based code if I could, though most of the pure markup techniques I was already aware of — such as using background images — were problematic in one way or other.

That’s when I reacquainted myself with the HTML DOM objects. Specifically the HTML DOM event onerror. The W3Schools website defines onerror as an event that “is triggered when an error occurs loading a document or an image”. This seemed to be the perfect solution to my problem.

In my code, the avatar element is initially loaded with the appropriate default image. The user is given the chance to add in their own image by inputting a URL into a text field. Once the user has submitted their new image URL, the avatar element’s src attribute would be updated via Javascript. Using the onerror attribute I was able to avoid writing extra logic into the Javascript code itself.

Here’s the final markup:

[html]</pre>
<img id="avatar" class="avatar" src="avatar.jpg" alt="avatar" />
<pre>[/html]

This particular project was already using jQuery so it made sense to take advantage of the .attr() method. For those of you not using jQuery, here’s a native Javascript version of the same markup:
[html]</pre>
<img id="avatar" class="avatar" src="avatar.jpg" alt="avatar" />
<pre>[/html]

This worked great and helped me to minimize the amount of logic in my Javascript code. It also allowed me to feel confident that the interface design wouldn’t end up looking broken in the case that the user entered an invalid image URL. On the surface, ‘onerror’ seemed to be a clever and useful tool from the HTML DOM events family.

The Bad

Web-standards, semantic markup, security and privacy, and cross-browser-compatibility are very important issues for me to consider in my daily work. When I’ve finally selected and implemented a solution to a given problem the job is typically far from over. I must then address the above issues and make sure the solution I’ve chosen isn’t sleazy, sneaky, or downright evil. I can’t recall the vast number of times the word ‘deprecated’ has stopped a seemingly good solution in its tracks and forced me to start from square one.

I was not as familiar with the onerror event as I am with the many other HTML DOM events and I began researching it to see if it was appropriate for use in a live project. What I found out – via this article – did not deter me from using onerror in this particular context, though it was quite alarming and definitely worth mentioning. It turns out that in a webpage where users are able to post (or otherwise add) their own content the onerror event can be used in a very exploitative way to hijack the webpage by using the following code:
[html]</pre>
<img src="not-a-valid-image-url" alt="" />
<pre>[/html]

The above code illustrates how a hijacker can force the page to redirect to a new location using the onerror event and how the hijacker can be sure this will happen by giving a invalid image URL in the element’s src attribute. Now imagine posting this on someone’s blog as a comment (or somehow otherwise injecting it into their webpage’s markup). It could do some serious damage and may be hard to locate if the webpage owner isn’t aware of what to look for and where. This can be prevented if you are implementing precautinoary security measures such as form validation and input cleansing (ie. the stripping of markup and tags upon submission).

The Ugly

Learning about the potential exploits and malicious uses of code that was originally created with good intent is very important to me, and sometimes the results I find mean ditching the solution and pursuing an alternative technique. While there are exploitative uses of the onerror event, they weren’t going to prevent me from using it in this context. However, I did uncover some more information that made this event a bit trickier to use than I’d initially thought.

I ran a test through the W3C Markup Validation Service and found out that the onerror event was not a valid attribute for an HTML element (nor an XHTML element). So while the code worked, it was not up to par with today’s standards and web practices.

Unfortunately the inelegance of using the onerror attribute doesn’t stop with it’s inability to validate. I’m very strict about keeping structure, style, and functionality as separate as possible. This means no inline CSS, and only using inline Javascript when it’s absolutely necessary. My original solution not only breaks the W3C’s validator and web-standards, but it also breaks my own personal rules about front-end code organization.

The interesting thing here is that on the W3Schools’ page onerror is listed as a valid HTML DOM event, but not an attribute. Which means I should be able to use it as long as it’s not added to an element inline. I did a bit more research and – inspired by this article – opted to use Javascript to add the onerror event to the required elements once the DOM had been fully read. Here’s the code:

[js]$( document ).ready( function () { $( ‘.avatar’ ).error( function () { this.src = ‘/img/avatar.jpg’; } ); } );[/js]

And here is the same code beautified (broken apart) so you can clearly see the logic involved:

[js]
$( document ).ready
(
function ()
{
$( ‘.avatar’ ).error
(
function ()
{
this.src = ‘/img/avatar.jpg’;
}
);
}
);
[/js]

As you can see, the code waits for the DOM to be ready before binding a function to the onerror event of any element with the ‘avatar’ class. This bound function changes the said element’s src attribute if the onerror event is triggered. Keep in mind that the above example relies on the .ready() and .error() methods from the jQuery framework.

For a Few Solutions More

For any problem there are always alternative solutions to be found, one of which is using pure CSS to apply a background image to the avatar element itself. There are three reasons I prefer not to use this method:

  1. Some browsers will automatically show a small icon to symbolize that the image has not been loaded, which will appear above our background image and probably look pretty slimy.
  2. Some browsers will automatically display the alt attribute text (which is a required attribute for valid XHTML markup these days) which will similarly appear above our background image and look even more disgruntled.
  3. CSS style rules for the avatar element in my project specify only a width value, allowing the height of the image to be variable, based on the actual size of the image. I do this so as not to distort the aspect ratio of the original image, yet allow the user to choose an image that is larger (or smaller) than the allowed avatar space. When a valid src value is not provided and no height is declared there is very good chance most browsers will not show the entire background image.

Given these three reasons, I found it most helpful to go the onerror route and believe I chosen a particularly applicable solution that satisifes my needs as well as my principles.

Working Example

W3Schools Tryit Editor v1.4

Resources

onerror (HTML attribute)
Check if an image is loaded (no errors) in Javascript

Are you smart? Innovative? Driven? If you’re interested in working on challenging projects in one of the world’s most fast-paced industries, why not check out the openings on our Careers page?

Back to news overview