Skip to content

focus on form submission : the order of keys in formLoader matters #160

Open
@franck-co

Description

When the form is submitted and the validation fails, the first invalid field is focused and this is great.

But this is not clear what is "the first" field.

After some testing, I realised that the order of the keys of the loader object matters.

Let's consider this simple form adapted from the playground :

export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
  field1: "",
  field2: "",
  field3: "",
  field4: "",
}));

export default component$(() => {
  // Use login form
  const [loginForm, { Form, Field }] = useForm<LoginForm>({
    loader: useFormLoader(),
  });

  return (
    <Form
      class="space-y-12 md:space-y-14 lg:space-y-16"
      onSubmit$={(values) => console.log(values)}
    >
      <FormHeader of={loginForm} heading="Login form" />
      <div class="space-y-8 md:space-y-10 lg:space-y-12">
      <Field
          name="field1"
          validate={[
            required('field1 is required'),
          ]}
        >
          {(field, props) => (
            <TextInput
              {...props}
              value={field.value}
              error={field.error}
              type="text"
              label="field1"
              required
            />
          )}
        </Field>       
         <Field
          name="field2"
          validate={[
            required('field2 is required'),
          ]}
        >
          {(field, props) => (
            <TextInput
              {...props}
              value={field.value}
              error={field.error}
              type="text"
              label="field2"
              required
            />
          )}
        </Field>
        <Field
          name="field3"
          validate={[
            required('field3 is required'),
          ]}
        >
          {(field, props) => (
            <TextInput
              {...props}
              value={field.value}
              error={field.error}
              type="text"
              label="field3"
              required
            />
          )}
        </Field>
        <Field
          name="field4"
          validate={[
            required('field4 is required'),
          ]}
        >
          {(field, props) => (
            <TextInput
              {...props}
              value={field.value}
              error={field.error}
              type="text"
              label="field4"
              required
            />
          )}
        </Field>
      </div>
      <FormFooter of={loginForm} />
    </Form>
  );
});

It has 4 required text fields.
As expected, if click on submit without filling the inputs, the first field is focused.

Let's swap the order of the fields in the routeLoader :

export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
- field1: "",
- field2: "",
- field3: "",
- field4: "",
+ field3: "",
+ field1: "",
+ field2: "",
+ field4: "",
}));

Now, when we click on submit, the third field is focused.

I've created a demo on this stackblitz : https://stackblitz.com/edit/modular-forms-qwik-zmtr8m?file=src%2Froutes%2Flogin%2Findex.tsx

I would have expected the order to be based on the DOM and tabindex.
Otherwise, the documentation should warn about this.

Metadata

Assignees

Labels

bugSomething isn't workingenhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions