Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: James Morrow
Ben Nadel at cf.Objective() 2010 (Minneapolis, MN) with: James Morrow ( @jmorrow_dev )

Anchor Tags Can Contain Block-Level Elements As Of HTML5

By Ben Nadel on
Tags: HTML / CSS

The world of web development moves quickly; and, it is often be hard for me to keep my mental model in alignment with the current trends and standards. Today, I learned that one of my internal rules was critically out of date. As of HTML5 - which was released years ago - it is OK to wrap block-level elements inside of an Anchor tag. In fact, pretty much the only thing you can't put inside of an Anchor tag is another Anchor tag. This new understanding is going to completely change my HTML markup choices.

Run this demo in my JavaScript Demos project on GitHub.

View this code in my JavaScript Demos project on GitHub.

Prior to HTML5, Anchor tags - <a> - could only contain "inline" elements (aka, "phrasing content"). To live comfortably within this specification, I often reached for embedded <span> tags that were styled to behave like block-level elements:

<a href="https://www.bennadel.com" class="block">
	<span class="block">
		Ben Nadel
	</span>
	<span class="block">
		Lover of JavaScript, HTML, and CSS.....
	</span>
</a>

Here, the <a> is semantically "correct" in that it only contains the inline elements <span>, even though both the <a> and <span> tags are styled to behave like block-level elements.

As of HTML5, however, such finagling is no longer needed. From the W3C specification for the Anchor tag:

Changes in HTML5

Although previous versions of HTML restricted the a element to only containing phrasing content (essentially, what was in previous versions referred to as "inline" content), the a element is now transparent; that is, an instance of the a element is now allowed to also contain flow content (essentially, what was in previous versions referred to as "block" content) - if the parent element of that instance of the a element is an element that is allowed to contain flow content.

This means that I can use just about anything that makes sense inside of an Anchor tag. To demonstrate, here's a "User Card" that is an Anchor tag that contains block-level elements:

<!doctype html>
<html lang="en">
<head>
	<meta charset="utf-8" />

	<title>
		Anchor Tags Can Contain Block-Level Elements As Of HTML5
	</title>

	<link rel="stylesheet" type="text/css" href="./style.css" />
</head>
<body>

	<h1>
		Anchor Tags Can Contain Block-Level Elements As Of HTML5
	</h1>

	<!--
		NOTE: This is an Anchor tag that contains the BLOCK Elements, Div and P. Prior
		to HTML5, this was not valid; however, as of HTML5, the Anchor tag can now
		contain both INLINE and BLOCK elements. Woot woot!
	-->
	<a href="https://www.bennadel.com" target="_blank" class="card">
		<img
			src="https://www.gravatar.com/avatar/f9bbc701ca6770ef482cc1e172344e25?s=120"
			alt="Avatar of Ben Nadel"
			class="avatar"
		/>
		<div class="name">
			Ben Nadel
		</div>
		<p class="description">
			Lover of JavaScript and Movies and Dogs and all things pudding. Free spirit
			with a rigid sense of timing.
		</p>
	</a>

</body>
</html>

As you can see, the <a> tag contains the block-level elements, <div> and <p>. If we run this page in the browser, we get the following output:

User Card that is made of an Anchor tag containing block-level elements in HTML5.

And, what's more, if we run this through the W3C Markup Validator, we get:

Document checking completed. No errors or warnings to show.

I know I'm like 5-10 years behind on this knowledge; which is to say, somewhat embarrassing. I think back to how many <span> tags have been used needlessly in an effort to author "correct" HTML. But no more! This particular gap in my mental model has been fixed. And, I will start reaching for more semantically correct elements, even when embedded within a block-styled Anchor tag.



Reader Comments

Be sure not to overlook that qualifier in the last part of the quoted spec: "... if the parent element of that instance of the a element is an element that is allowed to contain flow content."

i.e. an A which is a child of a SPAN or am EM cannot legally contain block elements.

Reply to this Comment

@Stephan,

That's a really good catch / point! My primary use-case for something like this is probably going to be in a list-item scenario like:

<li>
	<a href="#">
		<div class="some-blocky-thing">
			<!-- ... -->
		</div>
	</a>
</li>

So, for me, that's a limitation that I'll be able to work with.

Reply to this Comment

The last line in spec about the containing element to be flow was also new for me. Sometimes we learn from the comments as well.

Reply to this Comment

@Samiullah,

It's a group effort to learn all this stuff, am I right?! Too much for any one person to keep in their head, by far!

Reply to this Comment

Its useful but also can be used in the wrong way, I know the user card is an example but consider accessibility, wrapping lots of content in a single anchor can create issues for users of screen readers.

Have a read of this https://inclusive-components.club/cards/ there are techniques out there that can make a card completely clickable like everything is wrapped in an anchor when really it is only the necessary text,

Reply to this Comment

@Claudia,

I suppose that block-level elements are not arbitrarily exchangeable. Just because an Anchor tag can now contain block-level elements, I don't think that it means an Anchor can go anywhere.

Reply to this Comment

@Sean,

That's very interesting. I'm relatively new to thinking about accessability at this level. I will give your link a reading. I am wondering if we could perhaps using something like title to override the contents? Just thinking out-loud. I also see that there is a book by the author of that content, will definitely check that out!

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.