# Form Inputs Missing Labels

**MUST** · **ID:** `forms-rams-form-labels` · **Category:** forms
**Source:** [RAMS](https://www.rams.ai/)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/forms-rams-form-labels

> MUST: Every form input must have associated <label> with htmlFor, be wrapped by <label>, or have aria-label. Placeholder is not a substitute for labels.

All form inputs must have associated labels

Rams lists this as a Critical accessibility check (WCAG 1.3.1) in its review table; the upstream skill is a checklist, so that terse row is the whole rule. Why it matters: the label is what a screen reader announces on focus, and what a click target extends to. Placeholder text is not a substitute — it disappears the moment the user types.

## Bad — do not do this

`forms-rams-form-labels-bad`

```tsx
export function RamsFormLabelsBad() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4">
        <h4 className="font-medium mb-3">Inputs without Labels</h4>
        <form className="space-y-4" onSubmit={(e) => e.preventDefault()}>
          <div className="space-y-2">
            <span className="text-sm font-medium">Email address</span>
            {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
            <input
              type="email"
              placeholder="you@example.com"
              className="w-full px-3 py-2 border border-border rounded-md bg-background"
            />
          </div>
          <div className="space-y-2">
            <span className="text-sm font-medium">Password</span>
            {/* eslint-disable-next-line jsx-a11y/label-has-associated-control */}
            <input
              type="password"
              placeholder="Enter password"
              className="w-full px-3 py-2 border border-border rounded-md bg-background"
            />
          </div>
          <div className="bg-muted rounded p-2 font-mono text-xs">
            <code className="text-error">{'<span>Email</span><input />'}</code>
          </div>
        </form>
      </div>
      <p className="text-xs text-error">
        Screen reader announces only: "edit text" with no context
      </p>
    </div>
  );
}
```

## Good — do this

`forms-rams-form-labels-good`

```tsx
export function RamsFormLabelsGood() {
  return (
    <div className="w-full max-w-sm space-y-4">
      <div className="bg-card border border-border rounded-lg p-4">
        <h4 className="font-medium mb-3">Inputs with Labels</h4>
        <form className="space-y-4" onSubmit={(e) => e.preventDefault()}>
          <div className="space-y-2">
            <label htmlFor="good-email" className="text-sm font-medium">
              Email address
            </label>
            <input
              id="good-email"
              type="email"
              placeholder="you@example.com"
              className="w-full px-3 py-2 border border-border rounded-md bg-background"
            />
          </div>
          <div className="space-y-2">
            <label htmlFor="good-password" className="text-sm font-medium">
              Password
            </label>
            <input
              id="good-password"
              type="password"
              className="w-full px-3 py-2 border border-border rounded-md bg-background"
            />
          </div>
          <div className="bg-muted rounded p-2 font-mono text-xs">
            <code>{'<label htmlFor="email">Email</label>'}</code>
          </div>
        </form>
      </div>
      <p className="text-xs text-success">
        Screen reader announces: "Email address, edit text"
      </p>
    </div>
  );
}
```

## References

- [rams.md (skill source)](https://rams.ai/rams.md)
- [WCAG 1.3.1](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html)
