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.
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.)
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;