HTML Guides for a
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The HTML living standard defines a content model for the <a> element that explicitly excludes interactive content from appearing as descendants. Interactive content includes elements like <button>, <input>, <select>, <textarea>, and other <a> elements. When you nest an <input> inside a link, browsers face an ambiguous situation: should a click activate the link or interact with the input? Different browsers may handle this differently, leading to inconsistent behavior.
This restriction also matters for accessibility. Screen readers and other assistive technologies rely on a clear, predictable DOM structure. Nesting interactive elements creates confusion for users navigating with keyboards or screen readers, as the focus order and interaction model become unclear. A user tabbing through the page might not understand that an input lives inside a link, or they might be unable to interact with one of the two elements.
Common scenarios where this issue arises include wrapping a search input in a link to make the entire area clickable, or placing a checkbox inside a link to combine selection with navigation. In all cases, the solution is to separate the interactive elements.
Examples
❌ Incorrect: <input> inside an <a> element
<ahref="/search">
<inputtype="text"placeholder="Search...">
</a>
This triggers the validation error because <input> is interactive content nested inside <a>.
✅ Correct: Separate the elements
<formaction="/search">
<inputtype="text"placeholder="Search...">
<buttontype="submit">Search</button>
</form>
If the goal is to navigate to a search page, use a <form> with an action attribute instead of wrapping the input in a link.
❌ Incorrect: Checkbox inside a link
<ahref="/settings">
<inputtype="checkbox"id="notify"> Enable notifications
</a>
✅ Correct: Place the link and input as siblings
<label>
<inputtype="checkbox"id="notify"> Enable notifications
</label>
<ahref="/settings">Go to settings</a>
✅ Correct: Use styling to achieve a clickable area
If you want a visually combined area where clicking navigates somewhere, avoid using an <input> altogether and style the link instead:
<ahref="/search"class="search-link">
<span>Search...</span>
</a>
Alternatively, if you need both a link and an input near each other, use CSS layout to position them visually together while keeping them as separate elements in the markup:
<divclass="search-bar">
<inputtype="text"placeholder="Search...">
<ahref="/search">Go</a>
</div>
❌ Incorrect: Hidden input inside a link
Even hidden or non-visible inputs trigger this error:
<ahref="/page">
<inputtype="hidden"name="ref"value="home">
Click here
</a>
✅ Correct: Move the hidden input outside the link
<inputtype="hidden"name="ref"value="home">
<ahref="/page">Click here</a>
If the hidden input is meant to pass data during navigation, consider using query parameters in the link's href instead:
<ahref="/page?ref=home">Click here</a>
The <a> element is classified as interactive content, meaning it expects user interaction (clicking to navigate). The <label> element is also interactive — clicking a label activates or focuses its associated form control. When a <label> is nested inside an <a>, the browser faces an ambiguous situation: should a click navigate to the link's URL, or should it focus/activate the associated form control? The HTML specification resolves this by simply disallowing the nesting entirely.
According to the WHATWG HTML Living Standard, the content model of the <a> element is "transparent" but must not contain any interactive content. Since <label> is interactive content, it is not permitted as a descendant of <a> at any depth.
Beyond being invalid HTML, this nesting causes real problems:
- Accessibility: Screen readers may announce conflicting roles, confusing users who rely on assistive technology. The purpose of the element becomes unclear — is it a link or a form label?
- Unpredictable behavior: Different browsers may handle the click event differently, leading to inconsistent user experiences.
- Broken form association: The
<label>'sforattribute may not work as intended when the label is trapped inside a link.
The fix is straightforward: if you only need to style text inside a link, use a <span> or another non-interactive element instead of <label>. If you genuinely need both a link and a label, they should be separate, sibling elements rather than nested.
Examples
❌ Invalid: <label> inside <a>
<ahref="/settings">
<label>Account Settings</label>
</a>
This triggers the validation error because <label> is interactive content nested inside <a>.
✅ Fixed: Replace <label> with <span>
<ahref="/settings">
<span>Account Settings</span>
</a>
If the <label> was only used for styling purposes, a <span> with a CSS class achieves the same visual result without violating the specification.
❌ Invalid: <label> deeply nested inside <a>
<ahref="/profile">
<div>
<labelfor="username">Edit Username</label>
</div>
</a>
The rule applies to all descendants, not just direct children. This is still invalid.
✅ Fixed: Separate the link and label
<labelfor="username">Edit Username</label>
<ahref="/profile">View Profile</a>
When you need both a functional label and a link, keep them as siblings rather than nesting one inside the other.
✅ Fixed: Using <span> with a class for styling
<ahref="/dashboard">
<spanclass="label-style">Dashboard</span>
</a>
.label-style{
font-weight: bold;
text-transform: uppercase;
}
This preserves any visual styling you need while keeping the HTML valid and the interaction model unambiguous.
The <a> element is classified as interactive content, and the HTML spec explicitly states that interactive content must not be nested inside other interactive content. A <textarea> is a form control that accepts user input—clicking, focusing, typing, and selecting text within it. When it's wrapped in a link, the browser faces a conflict: should a click focus the textarea or follow the link? Different browsers may resolve this differently, leading to inconsistent behavior.
Beyond browser inconsistency, this nesting creates serious accessibility problems. Screen readers and other assistive technologies rely on a clear, predictable document structure. When a form control is buried inside a link, the roles and interaction models overlap, making it confusing or even impossible for users relying on keyboard navigation or screen readers to interact with either element properly.
The fix depends on what you're trying to achieve. If the <textarea> and the link are logically separate, simply move them to be siblings rather than nesting one inside the other. If you need them to appear visually grouped, use a wrapper <div> or another non-interactive container element instead.
Examples
❌ Invalid: <textarea> inside an <a> element
<ahref="/comments">
<textareaname="comment"rows="4"cols="40"></textarea>
</a>
This triggers the validation error because the <textarea> is a descendant of the <a> element.
✅ Valid: <textarea> and <a> as siblings
<div>
<textareaname="comment"rows="4"cols="40"></textarea>
<ahref="/comments">View all comments</a>
</div>
Here, both elements live side by side inside a neutral <div>, avoiding any nesting conflict.
✅ Valid: <textarea> inside a <form> with a separate link
<formaction="/submit-comment"method="post">
<labelfor="comment">Your comment:</label>
<textareaid="comment"name="comment"rows="4"cols="40"></textarea>
<buttontype="submit">Submit</button>
</form>
<ahref="/comments">View all comments</a>
This is the most semantically correct approach when the textarea is part of a form—keep the form controls in a <form> and place any navigation links outside of it.
Other interactive elements to watch for
The same rule applies to other interactive content inside <a> elements. You also cannot nest <button>, <input>, <select>, <details>, or another <a> inside a link. If the validator reports a similar error for any of these elements, the fix follows the same principle: move the interactive element out of the anchor.
The <a> element with an href attribute is one of HTML's most fundamental interactive elements. Browsers and assistive technologies inherently recognize it as a link — it's focusable via the Tab key, activatable with Enter, and announced as "link" by screen readers. This built-in behavior is part of the element's implicit ARIA role, which is link.
When you explicitly add role="link" to an <a href="..."> element, you're telling assistive technologies something they already know. The W3C validator flags this as unnecessary because it violates the principle of not redundantly setting ARIA roles that match an element's native semantics. This principle is codified in the first rule of ARIA use: "If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so."
While a redundant role="link" won't typically break anything, it creates noise in your markup. It can also signal to other developers that the role is necessary, leading to confusion or cargo-cult patterns. Clean, semantic HTML that relies on native roles is easier to maintain and less error-prone.
The role="link" attribute is legitimately useful when a non-interactive element like a <span> or <div> needs to behave as a link. In that case, you must also manually implement keyboard interaction (focus via tabindex, activation via Enter key handling) and provide an accessible name. But when you already have a proper <a> element with href, all of that comes for free — no ARIA needed.
Examples
❌ Incorrect: redundant role="link" on an anchor
<ahref="/about"role="link">About Us</a>
The role="link" is redundant here because the <a> element with href already has an implicit role of link.
✅ Correct: anchor without redundant role
<ahref="/about">About Us</a>
Simply remove the role="link" attribute. The browser and assistive technologies already treat this as a link.
✅ Correct: using role="link" on a non-semantic element (when necessary)
<spanrole="link"tabindex="0"onclick="location.href='/about'"onkeydown="if(event.key==='Enter')location.href='/about'">
About Us
</span>
This is the legitimate use case for role="link" — when you cannot use a native <a> element and need to make a non-interactive element behave like a link. Note the additional work required: tabindex="0" for keyboard focusability, a click handler, and a keydown handler for Enter key activation. Using a proper <a> element avoids all of this extra effort.
❌ Incorrect: multiple anchors with redundant roles
<nav>
<ahref="/"role="link">Home</a>
<ahref="/products"role="link">Products</a>
<ahref="/contact"role="link">Contact</a>
</nav>
✅ Correct: clean navigation without redundant roles
<nav>
<ahref="/">Home</a>
<ahref="/products">Products</a>
<ahref="/contact">Contact</a>
</nav>
The longdesc attribute was originally designed to point to a URL containing a detailed description of an element's content, primarily as an accessibility feature for screen reader users. On <iframe> elements, it was intended to describe the framed content for users who couldn't perceive it directly. However, the attribute was poorly implemented across browsers, rarely used by assistive technologies, and was ultimately removed from the HTML specification for <iframe> elements.
Using obsolete attributes causes W3C validation errors and can create a false sense of accessibility. Since browsers and assistive technologies don't reliably process longdesc on iframes, users who need the description may never actually reach it. A visible link, on the other hand, is universally accessible — it works for all users regardless of their browser, device, or assistive technology.
The fix is straightforward: remove the longdesc attribute from the <iframe> and place a regular <a> element near the iframe that links to the description page. This approach is more robust because the link is visible, discoverable, and works everywhere.
Examples
❌ Obsolete: Using longdesc on an <iframe>
<iframesrc="report.html"title="Annual report"longdesc="report-description.html"></iframe>
This triggers the validation error because longdesc is no longer a valid attribute on <iframe>.
✅ Fixed: Using a visible link instead
<iframesrc="report.html"title="Annual report"></iframe>
<p>
<ahref="report-description.html">Read a detailed description of the annual report</a>
</p>
The longdesc attribute is removed, and a descriptive link is placed adjacent to the iframe so all users can access it.
✅ Alternative: Wrapping in a <figure> for better semantics
For a more structured approach, you can use a <figure> element with a <figcaption> to associate the description link with the iframe:
<figure>
<iframesrc="report.html"title="Annual report"></iframe>
<figcaption>
Annual report overview.
<ahref="report-description.html">Read the full description</a>.
</figcaption>
</figure>
This groups the iframe and its caption together semantically, making the relationship between them clear to both sighted users and assistive technologies.
✅ Alternative: Using aria-describedby for additional context
If you want to provide a short inline description that assistive technologies can announce automatically, you can use aria-describedby:
<pid="report-desc">
This iframe contains the interactive annual report for 2024.
<ahref="report-description.html">Read the full description</a>.
</p>
<iframesrc="report.html"title="Annual report"aria-describedby="report-desc"></iframe>
This links the iframe to the descriptive paragraph programmatically. Screen readers will announce the content of the referenced element when the iframe receives focus, while the visible link remains available to all users.
Key Takeaways
- Always include a
titleattribute on<iframe>elements to describe their purpose — this is an important baseline accessibility practice. - Replace
longdescwith a visible<a>element that links to the long description. - Place the link near the iframe so users can easily find it.
- Consider using
<figure>and<figcaption>oraria-describedbyfor stronger semantic association between the iframe and its description.
The name attribute on the <a> element is obsolete in HTML5 and must be replaced with the id attribute.
Older versions of HTML used <a name="section1"> to create anchor targets within a page. HTML5 dropped this approach. The id attribute on any element now serves the same purpose, and it works on <a> tags as well as <div>, <section>, <h2>, or any other element. Fragment links like href="#section1" will scroll to whatever element has id="section1", regardless of element type.
The name attribute is still valid on elements like <input>, <form>, <meta>, and <map>, where it has a distinct function. On <a>, though, it has no valid use in modern HTML.
Invalid example
<aname="about">About us</a>
<p>Read more in our <ahref="#about">about section</a>.</p>
Valid example
<h2id="about">About us</h2>
<p>Read more in our <ahref="#about">about section</a>.</p>
If the anchor wraps content that has no better semantic element, a <span> or <div> with an id works fine:
<spanid="about">About us</span>
In older versions of HTML, the <a> element supported a shape attribute (with values like rect, circle, poly, and default) to define clickable hotspot regions within an image map. This feature was removed from the HTML specification, and the shape attribute is now considered obsolete on <a> elements.
The modern and correct way to create image maps is to use the <map> element containing one or more <area> elements. Each <area> element accepts a shape attribute along with coords to define clickable regions, and an href to specify the link destination. The <img> element is then associated with the map via its usemap attribute.
Why this matters
- Standards compliance: The
shapeattribute on<a>is not part of the current HTML living standard. Using it produces a validation error and relies on deprecated behavior that browsers are not required to support. - Browser compatibility: Modern browsers implement image maps through
<map>and<area>. Using the obsolete<a shape="...">syntax may not work reliably across browsers. - Accessibility: The
<area>element is designed to work with assistive technologies in the context of image maps. It supports thealtattribute, which provides text alternatives for each clickable region — something essential for screen reader users.
How to fix it
- Remove the
shapeattribute from any<a>elements. - Create a
<map>element with a uniquenameattribute. - Inside the
<map>, add<area>elements with the appropriateshape,coords,href, andaltattributes. - Associate the map with an
<img>element using theusemapattribute, referencing the map'snamewith a#prefix.
Examples
Incorrect: using shape on an <a> element
<imgsrc="workspace.png"usemap="#workspace"alt="Workspace diagram"width="400"height="300">
<mapname="workspace">
<ashape="rect"coords="0,0,200,150"href="/monitor.html">Monitor</a>
<ashape="circle"coords="300,200,50"href="/lamp.html">Desk lamp</a>
</map>
This triggers the validation error because the shape attribute is obsolete on <a> elements.
Correct: using <area> elements instead
<imgsrc="workspace.png"usemap="#workspace"alt="Workspace diagram"width="400"height="300">
<mapname="workspace">
<areashape="rect"coords="0,0,200,150"href="/monitor.html"alt="Monitor">
<areashape="circle"coords="300,200,50"href="/lamp.html"alt="Desk lamp">
</map>
Each <area> element defines a clickable region with shape and coords, links to a destination with href, and provides an accessible label with alt. The <area> element is a void element (no closing tag needed), and the alt attribute is required when href is present.
Supported shape values on <area>
| Value | Description | coords format |
|---|---|---|
rect | A rectangle | x1,y1,x2,y2 |
circle | A circle | centerX,centerY,radius |
poly | A polygon defined by multiple points | x1,y1,x2,y2,...,xn,yn |
default | The entire image area not covered by other shapes | No coords needed |
Example with multiple shape types
<imgsrc="floorplan.png"usemap="#floorplan"alt="Office floor plan"width="600"height="400">
<mapname="floorplan">
<areashape="rect"coords="10,10,200,150"href="/conference-room.html"alt="Conference room">
<areashape="circle"coords="400,300,60"href="/break-room.html"alt="Break room">
<areashape="poly"coords="300,10,350,80,250,80"href="/lobby.html"alt="Lobby">
<areashape="default"href="/office-overview.html"alt="General office area">
</map>
This example demonstrates all four shape types working together in a single image map, with proper alt text for each clickable region.
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries