Skip to content

Refactor ds-search-navbar so the <form> is only rendered when expanded (Pa11y H32 false positive) #5603

@bram-atmire

Description

@bram-atmire

Describe the bug

ds-search-navbar (src/app/search-navbar/search-navbar.component.html) keeps a <form> element in the DOM at all times, with a <button type="button"> instead of a real submit button:

<form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" autocomplete="on" class="d-flex">
  <input #searchInput ... name="query" formControlName="query" type="text" ...>
  <button class="submit-icon btn btn-link btn-link-inline"
          [attr.aria-label]="'nav.search.button' | translate"
          type="button"
          (click)="searchExpanded ? onSubmit(searchForm.value) : expand()"
          ...>
    <em class="fas fa-search fa-lg fa-fw"></em>
  </button>
</form>

Pa11y / HTMLCS reports rule WCAG2AA.Principle3.Guideline3_2.3_2_2.H32.2 ("This form does not contain a submit button") on this form on every page.

This is a partial false positive in functional terms: pressing Enter in the input does submit the form, because of HTML5 implicit submission - a form with a single text input is submitted on Enter even when there is no explicit submit button. The current implementation works.

However, the rule is flagging a real structural ambiguity: the same <form> is rendered in DOM both when the search is collapsed (where the icon's job is just to expand the input) and when it is expanded (where the icon's job is to submit). The dual purpose of the icon button is what forces it to be type="button", which is what makes the form structurally non-conformant to H32.

To Reproduce

  1. Run any DSpace 9 or 10 page (for example https://sandbox.dspace.org/) through Pa11y with the HTMLCS runner.
  2. Observe rule WCAG2AA.Principle3.Guideline3_2.3_2_2.H32.2 reported on ds-search-navbar > form on every page.
  3. Manually verify Enter still submits in the navbar (it does, via HTML5 implicit submission).

Expected behavior

The audit should not report this rule. Functionally Enter already works.

Suggested refactor

When the search is collapsed, do not render a <form> at all - render a single <button> (the magnifying-glass icon) whose only job is to expand. When the search is expanded, render the full <form> containing <input> and a real <button type="submit">.

Pseudo-template:

@if (!searchExpanded) {
  <button type="button" class="search-toggle btn btn-link btn-link-inline"
          [attr.aria-label]="'nav.search.button' | translate"
          (click)="expand()">
    <em class="fas fa-search fa-lg fa-fw"></em>
  </button>
} @else {
  <form [formGroup]="searchForm" (ngSubmit)="onSubmit(searchForm.value)" ...>
    <input #searchInput name="query" formControlName="query" type="text" ...>
    <button type="submit" class="submit-icon btn btn-link btn-link-inline"
            [attr.aria-label]="'nav.search.button' | translate">
      <em class="fas fa-search fa-lg fa-fw"></em>
    </button>
  </form>
}

This:

  • Removes the H32.2 false positive (when there is a form, it has a real submit button).
  • Makes the icon's role unambiguous in each state (toggle vs. submit).
  • Lets us drop the conditional (click) handler that branches on searchExpanded.
  • Preserves the existing animations and dsClickOutside collapse-on-blur logic by wrapping the conditional render in the same outer <div>.

Related work

  • WCAG 3.2.2 On Input (the rule the audit cites).
  • Pa11y / HTMLCS rule WCAG2AA.Principle3.Guideline3_2.3_2_2.H32.2.

Metadata

Metadata

Assignees

Type

Projects

Status

🏗 In Progress

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions