From 2c6ac73e0a4aad8a7497cd0e47bc30dc4a22bf23 Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 21 Nov 2023 15:07:30 +0100 Subject: [PATCH] web/flows: use aria-invalid attribute to better show invalid input fields (#7661) Signed-off-by: Jens Langhammer --- web/src/elements/forms/FormElement.ts | 24 +++++++++++++++---- web/src/flow/stages/password/PasswordStage.ts | 6 +++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/web/src/elements/forms/FormElement.ts b/web/src/elements/forms/FormElement.ts index bb408af88..b28c3bd7d 100644 --- a/web/src/elements/forms/FormElement.ts +++ b/web/src/elements/forms/FormElement.ts @@ -6,19 +6,20 @@ import { customElement, property } from "lit/decorators.js"; import PFForm from "@patternfly/patternfly/components/Form/form.css"; import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css"; +import PFBase from "@patternfly/patternfly/patternfly-base.css"; import { ErrorDetail } from "@goauthentik/api"; /** * This is used in two places outside of Flow, and in both cases is used primarily to - * display content, not take input. It displays the TOPT QR code, and the static + * display content, not take input. It displays the TOTP QR code, and the static * recovery tokens. But it's used a lot in Flow. */ @customElement("ak-form-element") export class FormElement extends AKElement { static get styles(): CSSResult[] { - return [PFForm, PFFormControl]; + return [PFBase, PFForm, PFFormControl]; } @property() @@ -28,7 +29,16 @@ export class FormElement extends AKElement { required = false; @property({ attribute: false }) - errors?: ErrorDetail[]; + set errors(value: ErrorDetail[] | undefined) { + this._errors = value; + const hasError = (value || []).length > 0; + this.querySelectorAll("input").forEach((input) => { + input.setAttribute("aria-invalid", hasError.toString()); + }); + this.requestUpdate(); + } + + _errors?: ErrorDetail[]; updated(): void { this.querySelectorAll("input[autofocus]").forEach((input) => { @@ -45,8 +55,12 @@ export class FormElement extends AKElement { : html``} - ${(this.errors || []).map((error) => { - return html`

${error.string}

`; + ${(this._errors || []).map((error) => { + return html`

+ + ${error.string} +

`; })} `; } diff --git a/web/src/flow/stages/password/PasswordStage.ts b/web/src/flow/stages/password/PasswordStage.ts index 774a1f5b3..36e301749 100644 --- a/web/src/flow/stages/password/PasswordStage.ts +++ b/web/src/flow/stages/password/PasswordStage.ts @@ -28,6 +28,11 @@ export class PasswordStage extends BaseStage 0; + } + renderInput(): HTMLInputElement { this.input = document.createElement("input"); this.input.type = "password"; @@ -38,6 +43,7 @@ export class PasswordStage extends BaseStage {