Form field labeled only via the title attribute
forms/title-only-label
- WCAG success criterion
- 1.3.1 (level A)
- Outcome class
- Hint only. An automated check that by design reports review hints only: its findings are marked for manual review, never as confirmed violations.
- Area
- Accessibility, Structure & Semantics
- Default severity
- medium
- axe-core rule
label-title-only
Why we flag this
The title attribute is read inconsistently or not at all by many screen readers; sighted users only see it on hover.
Form element without <label>/aria-label, name derived only from title.
What the rule checks
Scope. Rendered text-entry, select, slider and spinbutton fields (native or ARIA) without placeholder.
Expectation. Needs review when the field's name comes only from its title attribute: visible on mouse hover only, not to keyboard or touch users. H65 allows it when the purpose is clear from the visible context, so never a confirmed violation. A field with a label and a title is not reported; a field with a placeholder is forms/placeholder-as-label's case.
Source. WCAG 2.2 SC 1.3.1, 3.3.2; technique H65 (title attribute to identify form controls)
Detection: shared; needs dom, ax_tree.
Failing example
The check flags this for review. Corpus case forms_extended. The page may contain further findings for other rules.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Extended form checks corpus case</title>
<meta name="viewport" content="width=device-width, initial-scale=1"><style>
/* #783: page shell, so the case only reports what it is about */
.skip, nav a { display: inline-block; padding: 12px; min-height: 44px; min-width: 44px; box-sizing: border-box; }
button, input, select, textarea { min-height: 44px; min-width: 44px; box-sizing: border-box; }
input[type="checkbox"], input[type="radio"] { width: 44px; height: 44px; }
</style>
</head>
<body>
<a class="skip" href="#main">Skip to main content</a>
<header><p>Example Shop</p><nav aria-label="Main"><a href="/" aria-current="page">Home</a> <a href="/help">Help</a></nav></header>
<main id="main">
<h1>Error messages, context changes, labels, redundant entry, table headers</h1>
<input type="text" aria-invalid="true" aria-label="Email">
<select aria-label="Navigate to page" onchange="location.href=this.value">
<option value="/a">Page A</option>
<option value="/b">Page B</option>
</select>
<div onfocus="this.style.color='red'" tabindex="0">Non-interactive element with an onfocus handler</div>
<input type="text" title="Search the site">
<form>
<label for="email1">Email</label>
<input id="email1" name="email" type="email">
<label for="billing-email">Billing Email</label>
<input id="billing-email" name="billing_email" type="email">
<button type="submit">Submit</button>
</form>
<table>
<thead>
<tr><th id="col-name">Name</th></tr>
</thead>
<tbody>
<tr><td headers="does-not-exist">Alice</td></tr>
</tbody>
</table>
</main>
<footer><p>Example Shop, 2026</p></footer>
</body>
</html>Passing example
The check reports nothing here. Corpus case forms_labels, element input#lbl-title. The page may contain further findings for other rules.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Delivery preferences</title>
<style>
body { font-family: sans-serif; color: #222; background: #fff; line-height: 1.5; margin: 0 16px; }
a { color: #0050a0; }
.skip, nav a, .solo { display: inline-block; padding: 12px; min-height: 44px; min-width: 44px; box-sizing: border-box; }
button, input, select, textarea, [role="button"], [role="textbox"], [role="radio"], [role="link"], [role="searchbox"] {
display: inline-block; min-height: 44px; min-width: 44px; box-sizing: border-box; font-size: 1rem; }
input[type="checkbox"], input[type="radio"] { width: 44px; height: 44px; }
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
</style>
</head>
<body>
<a class="skip" href="#main">Skip to main content</a>
<header><p>Example Shop</p>
<nav aria-label="Main"><a href="/" aria-current="page">Home</a> <a href="/help">Help</a></nav>
</header>
<main id="main">
<h1>Delivery preferences</h1>
<!-- G2 #783: every labelling mechanism next to fields without one. A field needs a programmatic name (4.1.2, 1.3.1) and a visible label (3.3.2); a placeholder or title names it but is no lasting visible label. -->
<form action="/preferences" method="post">
<p><input id="coupon-code" name="coupon" type="text"></p>
<p><textarea id="gift-message" name="gift"></textarea></p>
<p><select id="wrap-style" name="wrap"><option>Plain</option><option>Festive</option></select></p>
<p><input id="voucher" name="voucher" type="text" placeholder="Voucher code"></p>
<p><input id="door-code" name="door" type="text" title="Door code"></p>
<p><label for="lbl-for">Gate number</label> <input id="lbl-for" name="gate" type="text"></p>
<p><label>Floor <input id="lbl-wrap" name="floor" type="text"></label></p>
<p><input id="lbl-aria" name="stairs" type="text" aria-label="Stairwell"></p>
<p><span id="bell-label">Doorbell label</span> <input id="lbl-by" name="bell" type="text" aria-labelledby="bell-label"></p>
<p><label for="lbl-ph">Courier note</label> <input id="lbl-ph" name="note" type="text" placeholder="Leave at the door"></p>
<p><label for="lbl-title">Drop-off spot</label> <input id="lbl-title" name="spot" type="text" title="Where to leave the parcel"></p>
<p><label for="lbl-select">Wrapping paper</label> <select id="lbl-select" name="paper"><option>Kraft</option><option>Gloss</option></select></p>
<p><label for="lbl-area">Card text</label> <textarea id="lbl-area" name="card"></textarea></p>
<p><span id="title-aria" role="textbox" contenteditable="true" tabindex="0" title="Gift note"></span></p>
<input type="hidden" name="token" value="abc">
<p><button type="submit">Save preferences</button></p>
</form>
</main>
<footer><p>Example Shop, 2026</p></footer>
</body>
</html>This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.