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
- Run any DSpace 9 or 10 page (for example https://sandbox.dspace.org/) through Pa11y with the HTMLCS runner.
- Observe rule
WCAG2AA.Principle3.Guideline3_2.3_2_2.H32.2 reported on ds-search-navbar > form on every page.
- 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.
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: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 betype="button", which is what makes the form structurally non-conformant to H32.To Reproduce
WCAG2AA.Principle3.Guideline3_2.3_2_2.H32.2reported onds-search-navbar > formon every page.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:
(click)handler that branches onsearchExpanded.<div>.Related work
WCAG2AA.Principle3.Guideline3_2.3_2_2.H32.2.