Skip to content
Back to Blog
TechnicalFormsAccessibility

Building agent-friendly forms: input types, labels, and validation

Agent Checker4 min read

Forms are the action layer of the web. When an AI agent books a flight, fills in a contact form, or completes a checkout, it is interacting with form elements. Poorly designed flows are why agents abandon complex checkouts so frequently. A form that is hard for agents to parse means failed tasks, frustrated users, and lost conversions.

Labels are non-negotiable

Every input needs a label. Not a placeholder, not a nearby <span>, not a tooltip. A proper <label> element with a for attribute that matches the input's id.

<!-- Bad: placeholder as label -->
<input type="text" placeholder="Enter your email" />

<!-- Bad: label is just nearby text -->
<span>Email</span>
<input type="text" />

<!-- Good: proper label association -->
<label for="email">Email address</label>
<input type="email" id="email" name="email" />

When an agent encounters a labelled input, it knows exactly what data to enter. With placeholder-only inputs, the label disappears the moment the agent starts typing, and there is no way to verify what the field expects.

Use correct input types

The type attribute on inputs tells agents what format the data should be in. This matters more than you might think.

<!-- Agent has to guess the format -->
<input type="text" name="user_email" />
<input type="text" name="phone" />
<input type="text" name="birthday" />

<!-- Agent knows exactly what to provide -->
<input type="email" name="user_email" />
<input type="tel" name="phone" />
<input type="date" name="birthday" />

The typed inputs also bring built-in browser validation, which helps agents know immediately if they have entered something wrong. A type="email" field will reject "not an email" before submission, giving the agent a chance to correct itself.

Here is a quick reference:

  • type="email" for email addresses
  • type="tel" for phone numbers
  • type="url" for web addresses
  • type="date" for dates (avoids ambiguous format problems)
  • type="number" with min and max for numeric values
  • type="search" for search inputs

Make validation messages accessible

When a form submission fails, the agent needs to know what went wrong and where. Many sites show validation errors as red text that only makes sense visually.

<!-- Bad: error only visible, not connected to input -->
<input type="email" name="email" class="error" />
<span class="text-red">Please enter a valid email</span>

<!-- Good: error connected to input via aria-describedby -->
<label for="email">Email address</label>
<input
  type="email"
  id="email"
  name="email"
  aria-invalid="true"
  aria-describedby="email-error"
/>
<span id="email-error" role="alert">Please enter a valid email address</span>

The aria-invalid attribute tells the agent this field has an error. The aria-describedby attribute points to the error message. The role="alert" ensures dynamic error messages are announced.

Group related fields

Use <fieldset> and <legend> to group related inputs. This is especially important for radio buttons and checkboxes.

<!-- Bad: agent cannot tell these radio buttons belong together -->
<label><input type="radio" name="size" value="s" /> Small</label>
<label><input type="radio" name="size" value="m" /> Medium</label>
<label><input type="radio" name="size" value="l" /> Large</label>

<!-- Good: grouped with context -->
<fieldset>
  <legend>Select size</legend>
  <label><input type="radio" name="size" value="s" /> Small</label>
  <label><input type="radio" name="size" value="m" /> Medium</label>
  <label><input type="radio" name="size" value="l" /> Large</label>
</fieldset>

Without the <fieldset>, an agent sees three disconnected radio buttons. With it, the agent knows these are size options for the same item.

Avoid custom select menus built from divs

Custom dropdown menus built from <div> elements with JavaScript are one of the biggest agent blockers. They look right to humans but are invisible or confusing to agents.

<!-- Agent cannot interact with this -->
<div class="custom-select" onclick="toggleDropdown()">
  <div class="selected">Choose colour</div>
  <div class="options hidden">
    <div class="option" data-value="red">Red</div>
    <div class="option" data-value="blue">Blue</div>
  </div>
</div>

<!-- Agent understands this immediately -->
<label for="colour">Colour</label>
<select id="colour" name="colour">
  <option value="">Choose colour</option>
  <option value="red">Red</option>
  <option value="blue">Blue</option>
</select>

If you must use a custom component, ensure it has proper ARIA roles (role="listbox", role="option") and keyboard interaction support. But a native <select> is always the safer choice.

Handle multi-step forms well

For multi-step forms (wizards, checkouts), agents need to know where they are in the process and what each step contains.

<form aria-label="Checkout">
  <fieldset>
    <legend>Step 2 of 3: Delivery address</legend>
    <!-- address fields here -->
  </fieldset>
  <button type="button" aria-label="Go back to step 1">Back</button>
  <button type="submit" aria-label="Continue to step 3">Continue</button>
</form>

The <legend> tells the agent which step it is on. The button labels explain where "Back" and "Continue" lead. Without this, an agent cannot reliably complete a multi-step process.

Test with actual agents

The best way to verify your forms work is to test them with Agent Checker or a browser agent. Try completing your form using Browser Use or a similar tool. Watch where it gets stuck. Nine times out of ten, the fix is a missing label, a custom widget without ARIA roles, or validation errors the agent cannot read.