Skip to content

ui: required form fields have no visual indicator — Bulk Import name/recipient, Tenant ID, and three others #680

Description

@smunini

Summary

Required form fields carry the HTML required attribute but nothing visible marks them as required. On the Bulk Import create form, "Submission Name" and "Recipient base URL" look identical to the four optional fields below them. The same is true of "Tenant ID" on the Tenants page. There is no required-field convention; one should be defined and applied wherever a form has a mix of required and optional inputs.

Current behavior

Open /ui/bulk-import and expand "Create Bulk Submission". Six text fields render, all with the same .field / .field__label / .field__input markup:

Field Required? Visual difference
Submission Name (crates/ui/templates/pages/bulk-import.html:24-27) yes — required none
Recipient base URL (:28-33) yes — required none
Submitter system (:35-39) no none
Submitter value (:40-44) no none
Submission ID (:45-49) no none

.field__label (crates/ui/assets/app.css:1169-1175) has no required variant, and there is no :required selector anywhere in app.css. The only signal the user gets is the browser's native validation bubble after they press submit — which arrives after the form is filled out, not while they are deciding what to fill in.

Same pattern on the Tenants add-tenant form (crates/ui/templates/pages/tenants.html:68-79): "Tenant Name" is optional and "Tenant ID" is required, and the two are visually identical.

Every required input in the app has this problem — there are only six:

  • crates/ui/templates/pages/bulk-import.html:26name
  • crates/ui/templates/pages/bulk-import.html:30recipient_base_url
  • crates/ui/templates/pages/bulk-import-detail.html:28manifest_url
  • crates/ui/templates/pages/tenants.html:76 — tenant id
  • crates/ui/templates/partials/search-builder.html:21 — query url

A required-marker convention does already exist, but only inside the schema-driven resource editor: crates/ui/templates/partials/editor-body.html:179 and :191 append <em>*</em> to required element names, styled at crates/ui/assets/app.css:3750-3753 as a non-italic accent-colored mark. Nothing outside the editor uses it.

Expected behavior

  • Required fields are visually distinguishable from optional ones before submit — a marker on the label, following one convention across the app.
  • The convention is the same one the resource editor already uses, or a deliberate replacement applied to both.
  • The marker is not the only signal for assistive tech: required stays on the input, and if the marker is a bare glyph it is either aria-hidden with an accessible-name alternative or given text the screen reader can read.
  • Applied to all five required inputs listed above, not just Bulk Import.

Evidence

  • crates/ui/templates/pages/bulk-import.html:24-49 — required and optional fields, indistinguishable markup
  • crates/ui/templates/pages/tenants.html:68-79 — optional display_name next to required id
  • crates/ui/assets/app.css:1169-1200.field__label / .field__input / .field__hint; no required variant, no :required rule
  • crates/ui/templates/partials/editor-body.html:179, :191 and crates/ui/assets/app.css:3750-3753 — the existing <em>*</em> marker, editor-only
  • crates/ui/src/bulk_import.rs:291-330CreateForm takes name and recipient_base_url as non-optional String, confirming which fields the server actually needs

Suggested approach

  1. Add a .field__label--required (or a .field__req span) to app.css reusing the editor's treatment — accent-colored, non-italic marker — and document it in crates/ui/README.md alongside the copy conventions.
  2. Decide the accessible spelling: either the marker carries aria-hidden="true" and the input keeps required (screen readers announce "required" from the attribute), or the label includes a localized "required" word. Pick one and apply it everywhere.
  3. Apply to the five required inputs listed above.
  4. Consider whether the inverse convention is better for forms that are mostly required — marking the optional fields instead. The Bulk Import form is 2 required of 6, so marking required is the right call there.
  5. Add the marker string to locales/en|de|es/main.ftl if the chosen approach needs localized text.

Scope / out of scope

Visual and accessible marking of required fields. Not in scope: changing which fields are required, adding client-side validation beyond what required already does, or restyling the error state shown after a failed submit (error presentation is tracked in #676).

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingui

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions