# Handle submission

Now your first form is almost ready. There is only one little thing missing and that is the data processing when the form is submitted.

## Submit event

To process the values on submission, you need to pass a function to the `onSubmit$` property of the <Link href="/qwik/api/Form/">`Form`</Link> component. The first parameter passed to the function contains the validated form values.

```tsx
import { Field, Form, type SubmitHandler, useForm$ } from '@formisch/qwik';
import { $, component$ } from '@qwik.dev/core';
import * as v from 'valibot';

const LoginSchema = v.object({
  email: v.pipe(v.string(), v.email()),
  password: v.pipe(v.string(), v.minLength(8)),
});

export default component$(() => {
  const loginForm = useForm$(() => ({
    schema: LoginSchema,
  }));

  const submitForm = $<SubmitHandler<typeof LoginSchema>>((values) => {
    // Process the validated form values
    console.log(values); // { email: string, password: string }
  });

  return (
    <Form of={loginForm} onSubmit$={submitForm}>
      {/* Form fields will go here */}
    </Form>
  );
});
```

The <Link href="/core/api/SubmitHandler/">`SubmitHandler`</Link> type ensures type safety for your submission handler, automatically inferring the types of validated values from your schema. If you need access to the submit event, use <Link href="/core/api/SubmitEventHandler/">`SubmitEventHandler`</Link> instead.

### Prevent default

When the form is submitted, `event.preventDefault()` is executed by default to prevent the window from reloading so that the values can be processed directly in the browser and the state of the form is preserved.

### Loading state

While the form is being submitted, you can use `loginForm.isSubmitting.value` to display a loading animation and disable the submit button:

```tsx
<button type="submit" disabled={loginForm.isSubmitting.value}>
  {loginForm.isSubmitting.value ? 'Submitting...' : 'Login'}
</button>
```

The form store also provides other reactive properties like `isSubmitted`, `isValidating`, `isTouched`, `isDirty`, `isValid`, and `errors` for tracking form state. Note that `errors` only contains validation errors at the root level of the form — to get all errors from all fields, use the <Link href="/methods/api/getAllErrors/">`getAllErrors`</Link> method.

### Async submission

The submit handler can be asynchronous, allowing you to perform API calls or other async operations:

```tsx
const submitForm = $<SubmitHandler<typeof LoginSchema>>(async (values) => {
  try {
    const response = await fetch('/api/login', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(values),
    });

    if (response.ok) {
      // Handle successful login
      console.log('Login successful!');
    } else {
      // Handle error
      console.error('Login failed');
    }
  } catch (error) {
    console.error('Error during submission:', error);
  }
});
```

### Trigger submission

If you want to trigger submission programmatically from outside the form, you can use the <Link href="/methods/api/submit/">`submit`</Link> method. It calls `requestSubmit()` on the underlying form element:

```tsx
import { submit } from '@formisch/qwik';

<button type="button" onClick$={() => submit(loginForm)}>
  Submit from outside
</button>;
```

## Submit without \<form /\>

In some cases, you may not be able to wrap your fields in a `<form>` element — for example, when your form is rendered inside another form, since nesting `<form>` elements is invalid HTML. In these situations, you can use the <Link href="/methods/api/handleSubmit/">`handleSubmit`</Link> method directly to submit the form programmatically without the <Link href="/qwik/api/Form/">`Form`</Link> component.

The returned function accepts no arguments and can be called from anywhere — for example, from a button's `onClick$` handler:

```tsx
import { Field, handleSubmit, useForm$ } from '@formisch/qwik';
import { $, component$ } from '@qwik.dev/core';
import * as v from 'valibot';

const LoginSchema = v.object({
  email: v.pipe(v.string(), v.email()),
  password: v.pipe(v.string(), v.minLength(8)),
});

export default component$(() => {
  const loginForm = useForm$(() => ({
    schema: LoginSchema,
  }));

  const submitForm = $(
    handleSubmit(loginForm, (values) => {
      // Process the validated form values
      console.log(values);
    })
  );

  return (
    <div>
      {/* Form fields without a <Form /> wrapper */}
      <button type="button" onClick$={submitForm}>
        Login
      </button>
    </div>
  );
});
```

## Next steps

Congratulations! You've learned the core concepts of building forms with Formisch. To learn more about advanced features, check out the <Link href="/qwik/guides/form-methods/">form methods</Link> guide to discover how to programmatically control your forms.
