# axe-core label-title-only error form element needs visible label - how to fix it

## TL;DR

The label-title-only rule fires when a control's only label is invisible: a title attribute, aria-describedby, or a visually hidden label. Add a real visible label next to the control, for example [label for="search"]Search[/label], and keep the title attribute as a supplement if you like. If the design truly has no room for a visible label, a visible placeholder-plus-hint pattern or redesigning the layout beats hiding the label.

Design teams often push back on visible labels for aesthetic reasons, especially on search fields and newsletter inputs. The compromise that passes the rule is a visible label styled small or placed adjacent, not a hidden one. If the product owner insists on no visible label, document the exception and the user impact explicitly; do not quietly ship the violation.

The verbatim error looks like this:

```text
axe-core 4.x
Rule: label-title-only (serious)
"Form elements should have a visible label"

Element: [input type="text" id="search" title="Search the docs"]
  Labeled only by the title attribute; no visible label present.
```

## Steps

1. Confirm the rule id in a focused scan:

```bash
npx @axe-core/cli https://example.com/docs --rules label-title-only
```

Expected: the flagged control is listed with rule id label-title-only.

2. Identify how the control is currently labeled. Check for a title attribute, an aria-describedby pointing at hint text, or a label styled with a visually-hidden class. That invisible-only label is what the rule objects to.

3. Add a visible label element tied to the control:

```html
[label for="search"]Search the docs[/label]
[input type="search" id="search" title="Search the docs"]
```

Keep the existing title or hint; the rule only demands that a visible label also exists.

4. Re-run the focused scan from step 1. Expected output: 0 violations for label-title-only.

5. Spot-check the whole form with the broader label rules to catch siblings of the same bug:

```bash
npx @axe-core/cli https://example.com/docs --rules label,title-only
```

Expected: no label-family violations remain.

6. Audit the whole form, not just the flagged field. The label-title-only pattern is usually systemic: one component or one CSS class hides labels everywhere. Search the codebase for visually-hidden label patterns and title-only inputs:

```bash
rg -l 'title=' src/components/forms/ | head -20
```

7. Update the component or template so labels render visibly by default. If the design system has a 'hidden label' variant, deprecate it or gate it behind an explicit prop with a comment explaining the accessibility cost.
## When to use

- Axe flags label-title-only on inputs, selects, or textareas.
- A design-system audit shows fields labeled only by title attributes or hidden labels.
- Placeholder text is doing the job of a label (placeholders vanish on input and are not a label).

## When not to use

- The control has no accessible name at all (that is a *-name rule such as select-name or aria-input-field-name).
- The control is an icon-only button where the visible-label exception is intentional (use aria-label and document the exception).
- You are auditing a third-party widget you cannot restyle (file it with the vendor instead).

## Why it happens

Visible labels help everyone: sighted users scanning a form, users with cognitive disabilities who lose context when placeholders disappear, and screen reader users who get the same name announced. A title-only label is invisible to most sighted users, so the field looks unlabeled to them, and assistive tech treats title as a weak, low-priority name. The rule pushes the label out of hiding.

The title attribute was never designed to be a label. Browsers show it as a tooltip on hover, which mouse users may never trigger and touch users cannot trigger at all, and assistive tech treats it as a last-resort name. The pattern became common because title is easy to add without touching layout. Every framework's form component library has at least one title-labeled input that has been failing this rule since axe 4.1 added it.

## Edge cases

- Search boxes with a magnifier icon and no label are the classic offender. A visible 'Search' label or an always-visible hint line next to the field satisfies the rule.
- Floating-label patterns pass only if the label is visible in the resting state. If the label only appears on focus, axe still flags it.
- aria-label on the control does not satisfy this rule. The rule specifically wants a visible label, not just any accessible name.
- Composite widgets (date pickers, rich selects) may need the visible label on the wrapper with aria-labelledby pointing at it.
- Placeholder attributes are not labels either. A placeholder that disappears on input fails both this rule's spirit and usability heuristics.
- In right-to-left layouts, the for/id association is direction-independent, but visually place the label where RTL readers expect it.
- Checkbox and radio groups need a visible [legend] or group label, not just per-option labels. The rule can flag the group when options are title-labeled.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_XTO7hSZcAlaBF8iaETaGvA
