From d34bd53275875fcf7b142e9412ac8b78454ea424 Mon Sep 17 00:00:00 2001 From: Nicolas Meienberger Date: Wed, 18 Feb 2026 19:33:58 +0100 Subject: [PATCH] refactor: scroll to first error when submitting a form --- app/client/hooks/use-scroll-to-form-error.ts | 10 ++++++++++ .../backups/components/create-schedule-form/index.tsx | 5 ++++- .../components/create-notification-form.tsx | 8 +++++++- .../repositories/components/create-repository-form.tsx | 8 +++++++- .../modules/volumes/components/create-volume-form.tsx | 8 +++++++- 5 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 app/client/hooks/use-scroll-to-form-error.ts diff --git a/app/client/hooks/use-scroll-to-form-error.ts b/app/client/hooks/use-scroll-to-form-error.ts new file mode 100644 index 00000000..2e5ebc67 --- /dev/null +++ b/app/client/hooks/use-scroll-to-form-error.ts @@ -0,0 +1,10 @@ +import { useCallback } from "react"; + +export function useScrollToFormError() { + return useCallback(() => { + setTimeout(() => { + const firstError = document.querySelector("[data-slot='form-message']"); + firstError?.scrollIntoView({ behavior: "smooth", block: "center" }); + }, 50); + }, []); +} diff --git a/app/client/modules/backups/components/create-schedule-form/index.tsx b/app/client/modules/backups/components/create-schedule-form/index.tsx index 21007ca7..a760323c 100644 --- a/app/client/modules/backups/components/create-schedule-form/index.tsx +++ b/app/client/modules/backups/components/create-schedule-form/index.tsx @@ -1,6 +1,7 @@ import { arktypeResolver } from "@hookform/resolvers/arktype"; import { useCallback, useState } from "react"; import { useForm } from "react-hook-form"; +import { useScrollToFormError } from "~/client/hooks/use-scroll-to-form-error"; import { Form } from "~/client/components/ui/form"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "~/client/components/ui/card"; import type { BackupSchedule, Volume } from "~/client/lib/types"; @@ -30,6 +31,8 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }: defaultValues: backupScheduleToFormValues(initialValues), }); + const scrollToFirstError = useScrollToFormError(); + const handleSubmit = useCallback( (data: InternalFormValues) => { const { @@ -100,7 +103,7 @@ export const CreateScheduleForm = ({ initialValues, formId, onSubmit, volume }: return (
diff --git a/app/client/modules/notifications/components/create-notification-form.tsx b/app/client/modules/notifications/components/create-notification-form.tsx index f4473125..d166f858 100644 --- a/app/client/modules/notifications/components/create-notification-form.tsx +++ b/app/client/modules/notifications/components/create-notification-form.tsx @@ -15,6 +15,7 @@ import { import { Input } from "~/client/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "~/client/components/ui/select"; import { notificationConfigSchemaBase } from "~/schemas/notifications"; +import { useScrollToFormError } from "~/client/hooks/use-scroll-to-form-error"; import { CustomForm, DiscordForm, @@ -116,11 +117,16 @@ export const CreateNotificationForm = ({ onSubmit, mode = "create", initialValue }); const { watch } = form; + const scrollToFirstError = useScrollToFormError(); const watchedType = watch("type"); return ( - + ("default"); const { capabilities } = useSystemInfo(); + const scrollToFirstError = useScrollToFormError(); return ( - + (null); @@ -102,7 +104,11 @@ export const CreateVolumeForm = ({ onSubmit, mode = "create", initialValues, for return ( - +