diff --git a/console/src/formkit/formkit.config.ts b/console/src/formkit/formkit.config.ts index 78b90628b..76cfd06ee 100644 --- a/console/src/formkit/formkit.config.ts +++ b/console/src/formkit/formkit.config.ts @@ -24,6 +24,7 @@ import radioAlt from "./plugins/radio-alt"; import stopImplicitSubmission from "./plugins/stop-implicit-submission"; import passwordPreventAutocomplete from "./plugins/password-prevent-autocomplete"; import requiredAsterisk from "./plugins/required-asterisk"; +import autoScrollToErrors from "./plugins/auto-scroll-to-errors"; const config: DefaultConfigOptions = { config: { @@ -34,6 +35,7 @@ const config: DefaultConfigOptions = { stopImplicitSubmission, passwordPreventAutocomplete, requiredAsterisk, + autoScrollToErrors, ], inputs: { form, diff --git a/console/src/formkit/plugins/auto-scroll-to-errors.ts b/console/src/formkit/plugins/auto-scroll-to-errors.ts new file mode 100644 index 000000000..78dee5e9f --- /dev/null +++ b/console/src/formkit/plugins/auto-scroll-to-errors.ts @@ -0,0 +1,34 @@ +import type { FormKitNode } from "@formkit/core"; + +export default function autoScrollToErrors(node: FormKitNode) { + const scrollTo = (node: FormKitNode) => { + if (!node.props.id) { + return; + } + const el = document.getElementById(node.props.id); + if (el) { + el.scrollIntoView({ block: "end", inline: "nearest" }); + } + }; + + const scrollToErrors = () => { + node.walk((child) => { + if (child.ledger.value("blocking") || child.ledger.value("errors")) { + scrollTo(child); + return false; + } + }, true); + }; + + if (node.props.type === "form") { + const onOldSubmitInvalid = node.props.onSubmitInvalid; + node.props.onSubmitInvalid = () => { + if (onOldSubmitInvalid) { + onOldSubmitInvalid(node); + } + scrollToErrors(); + }; + node.on("unsettled:errors", scrollToErrors); + } + return false; +}