TT Lab
Get started
Learn Learning paths Courses

HTML — One Tag Stands In For a Feature

Getting Rid of Nameless Fields

Continue in TT Lab

Goal

You write one signup form and check whether an accessible name is actually computed for every field. There is no browser, but name computation has a single answer from markup alone.

Why it matters

"Did I write a label" can be counted by eye, but that can't catch a field where for and id don't match. What a machine sees is not the text but the computed result, and that computation has a defined order — aria-labelledby → aria-label → label → title → placeholder.

If an earlier step yields a value, the later ones are not looked at. So a single aria-label overwrites the visible label entirely, and the text written on screen and the voice diverge. Voice-control users say the visible text, so at that moment they can't operate it.

What to build

It is a single file, /root/work/forms/signup.html. No CSS or JavaScript is needed — what this lab looks at is whether the connection holds.

The calculator

cd /root/work/forms
python3 /opt/lab/checks/html-form-lab/accname.py signup.html

For each field it shows the name and where that name came from. It also prints broken aria-labelledby and aria-describedby references.

Steps

  1. Document skeleton, form, and a submit button
  2. Three fields · the name comes from label
  3. A radio group · fieldset and legend
  4. Rule guidance with aria-describedby
  5. The error state — aria-invalid and role="alert"
  6. type and autocomplete
  7. Required marking — for the eye and for the program
  8. Save the calculator's result as 08-names.txt
  9. Wrap-up → 09-notes.md

Notes

Set up a form

Create /root/work/forms/signup.html. It must have <!doctype html>, <html lang="ko">, <title>, <meta charset>, and <meta name="viewport">, and inside a <form> with action and method there must be one input field and a submit <button>.

Run mkdir -p /root/work/forms. If you write action and method, the form is still submitted even if JavaScript dies — that is the form's default. Submit with a button. input type="submit" also works, but you can't put an icon or other elements inside the button.

Where does the name come from

Increase the input fields to three or more, and make every field's name come from label. The 출처= value (the Korean word for "source") that the calculator prints must be label for all three fields. If you patch over a name with placeholder or title, it fails.

The for of a label and the id of the input must not differ by even one character. To the eye they sit side by side, but to a machine they are strangers. First see where the name currently comes from with python3 /opt/lab/checks/html-form-lab/accname.py signup.html.

A group has a name of its own

Make two or more radio buttons with the same name, put them inside one <fieldset>, and give the group a name with <legend>. Each radio must also have its own label.

Radios together form one question. Even if each option has a name, nowhere does it say "what you are choosing" — the legend fills that spot. The name must be the same for them to deselect each other.

A rule is a description, not a name

Write the password rule guidance as a separate element and connect it with aria-describedby. The description text must be at least 10 characters, and it must not be the same sentence as the name.

If you shove the rule inside the label, the field's name becomes "Password at least twelve characters including digits and symbols…". A name has to be short to be chosen from a list. Separate long guidance out as a description.

Make the error readable by a program

Give the email field aria-invalid="true", and list two elements, the help text and the error message, in aria-describedby separated by a space. Attach role="alert" to the error message element.

A red border means nothing to someone who can't distinguish colors. aria-describedby accepts several ids — point to both so the rule guidance doesn't disappear when an error appears. Text that appears later is read only if it has role="alert".

Keystrokes are accessibility too

Increase the text-entry fields to four (add a contact field) and give all of them standard autocomplete values. The email field gets type="email" and autocomplete="email", and the password gets new-password.

A value not in the HTML Standard's list of autofill field names is simply ignored by the browser — e-mail does nothing. Use new-password for signup and current-password for login. Only with this distinction does a password manager suggest a new password.

Required must be visible to the eye too

Give required to two or more fields, and put a required marking in those fields' label text too. You must leave at least one optional field, and the name of an optional field must have no required marking.

With aria-required alone, it only informs and the browser's submission blocking isn't turned on. Conversely, with required alone, the eye can't tell which field is required. You need both. If you make everything required, the marking tells you nothing.

Check with the calculator

Run accname.py and save the result as /root/work/forms/08-names.txt. The number of saved lines must equal the number of controls in the current document, and there must be no 출처=placeholder (the first word is the Korean word for "source") or broken-reference warnings.

python3 /opt/lab/checks/html-form-lab/accname.py signup.html | tee 08-names.txt. If you changed the document, you have to save again — the grader compares the saved copy with the current document.

What is a connection and what is text

In /root/work/forms/09-notes.md, write at least three lines (at least 120 characters). The text must contain placeholder, fieldset, and 이름 (the Korean word for "name"). The document itself must also still pass the step 2 criteria.

The core is one thing — a connection is a computation, not text. If you write down in your own words which mistakes create the state "the markup looks fine but there is no name," your hands will remember next time.