Skip to main content
Version: next

Manage forms

Learn how to build consistent and accessible forms with Front-Commerce's pre-built components.

In Front-Commerce, we have implemented default Form inputs that try to make things easier in your daily life as a developer.

Form declaration

In order to learn about Form components in Front-Commerce, let's build a contact form. When building standard HTML forms, a form would look like this:

<form method="post">
<div>
<label for="email">Email</label>
<input id="email" name="email" type="email" />
</div>

<div>
<label for="content">Content</label>
<textarea id="content" name="content"></textarea>
</div>

<button type="submit">Send</button>
</form>

If we were to transform this with Front-Commerce components, it would instead look like this:

import { Form } from "@remix-run/react";
import FormItem from "theme/components/molecules/Form/Item";
import FormActions from "theme/components/molecules/Form/FormActions";
import Fieldset from "theme/components/atoms/Forms/Fieldset";
import { Email, Textarea } from "theme/components/atoms/Forms/Input";
import SubmitButton from "theme/components/atoms/Button/SubmitButton";

const MyForm = () => {
return (
<Form method="post">
<Fieldset large={true} appearance="default">
<FormItem label="Email">
<Email id="email" name="email" />
</FormItem>

<FormItem label="Content">
<Textarea id="content" name="content" />
</FormItem>
</Fieldset>

<FormActions>
<SubmitButton>Send</SubmitButton>
</FormActions>
</Form>
);
};

export default MyForm;

By using Front-Commerce's components you will ensure that all fields look the same way across your application. They will also add validations and accessibility features by default.

You can for instance use features like required or disabled just like in HTML, but have relevant error messages.

info

Here is a list of default form components that might prove to be useful in your project:

  • Form inputs (theme/components/atoms/Forms/Input): exports the different type of inputs available (Checkbox, CountrySelect, Email, Hidden, NumberInput, Password, Radio, RadioGroup, Select, Tel, Text, Textarea)
  • Form item (theme/components/molecules/Form/Item): states how to display a label next to a field.
  • Fieldset (theme/components/atoms/Forms/Fieldset): A fieldset tag with style applied
  • Form Actions (theme/components/molecules/Form/FormActions): organizes buttons at the end of a form (centered, vertical, etc.)

The exhaustive list can be found here and here.

info

For more detailed information on form submission using Remix, please refer to the following guides:

Form advanced use cases

You will most likely need to develop behaviors that are not explained by the above sections. Here is the list of the most common use cases and pointers to learn about how to implement them.

Default values

To define a default value on an input you need to pass the defaultValue property.

For instance, if you already know the email address of the user, you can prefill the email field like this:

<Email id="email" name="email" defaultValue={user.email} />

Use an input outside of a form

Having input in a <Form> component is a good practice and improves accessibility. However, you may have a specific use case forcing you to use an input outside of a <Form> component.

To do so, you will need to pass an onChange property to your input. By doing this, you won't have anything in your root Form component but will be able to observe the input's changes directly.

<Email
id="email"
name="email"
value={currentValue}
onChange={(newValue) => {
console.log("new value", newValue);
}}
/>

You can see this as going back to the standard way of handling form inputs in React. However you will keep the same appearance and behaviors than the rest of the inputs in your website.

Reset a form after its submission

To reset a form after its submission with Remix, you can use the useFetcher hook along with a useRef to reference the form or input elements. After the form is successfully submitted, you can reset the form or input fields by setting their values to an empty string. Here is an example:

import { useFetcher } from "@remix-run/react";
import { useRef, useEffect } from "react";
import { SubmitButton } from "theme/components/atoms/Button";
import Input from "theme/components/atoms/Forms/Input/Input";
import type { action } from "routes/api/todoList";

const MyFormComponent = () => {
const fetcher = useFetcher<typeof action>();
const formRef = useRef<HTMLFormElement>(null);

useEffect(() => {
if (fetcher.state === "idle" && fetcher.data) {
if (formRef.current) {
formRef.current.reset();
}
}
}, [fetcher.state, fetcher.data]);

return (
<fetcher.Form method="post" action={`/api/todoList`} ref={formRef}>
<Input id="todo" type="text" name="todo" />
<SubmitButton>Submit</SubmitButton>
</fetcher.Form>
);
};

export default MyFormComponent;

In this example, the form is reset using the reset method on the form reference when the fetcher state is idle and data is available, indicating that the form submission has completed.

New input types

The available inputs in Front-Commerce should cover most of your use cases. However, this might not be sufficient and you may need to implement your own form field from scratch.

To do so, we recommend to use forwardRef. Here is an exemple on how we use it for the Email input :

import { forwardRef } from "react";
import Input, {
type InputProps,
} from "theme/components/atoms/Forms/Input/Input";

export type EmailProps = Omit<InputProps, "type">;

const Email = forwardRef<HTMLInputElement, EmailProps>((props, ref) => {
return <Input {...props} ref={ref} type="email" />;
});

Email.displayName = "Email";

export default Email;