# Form
Redwood provides several helpers to make your life easier when working with forms. All of Redwood's form helpers are simple wrappers around react-hook-form that makes it even easier to use in many cases. If Redwood's form helpers aren't flexible enough for you, you can always use react-hook-form
directly, or use any other form builder that works with React.
WARNING: RedwoodJS software has not reached a stable version 1.0 and should not be considered suitable for production use. In the "make it work; make it right; make it fast" paradigm, Redwood is in the later stages of the "make it work" phase.
Redwood currently provides the following form components:
<Form>
surrounds all form elements and provides contexts for errors and form submission<FormError>
displays an error message, typically at the top of your form, containing error messages from the server<Label>
is used in place of the HTML<label>
tag and can respond to errors with different styling<SelectField>
is used in place of the HTML<select>
tag and responds to errors with different styling<TextAreaField>
is used in place of the HTML<textarea>
tag and can accept validation options and be styled differently in the presence of an error The default validation forrequired
isfalse
for this field, To make it required, please pass the propvalidation={{ required: true }}
for all the<RadioField>
.<FieldError>
will display error messages from form validation and server errors<Submit>
is used in place of<button type="submit">
and will trigger a validation check and "submission" of the form (actually executes the function given to theonSubmit
attribute on<Form>
)- HTML
<input>
types are available as a component<TypeField>
whereType
is one of the official HTML types. They can accept validation options and be styled differently in the presence of an error. We'll refer to these collectively as "InputFields" below. The full list is:<ButtonField>
<CheckboxField>
<ColorField>
<DateField>
<DatetimeLocalField>
<EmailField>
<FileField>
<HiddenField>
<ImageField>
<MonthField>
<NumberField>
<PasswordField>
<RadioField>
<RangeField>
<ResetField>
<SearchField>
<SubmitField>
<TelField>
<TextField>
<TimeField>
<UrlField>
<WeekField>
Some fields also share options:
<Label>
, <TextAreaField>
and all InputFields take similar options for styling in the presence of an error.
The <TextAreaField>
and all InputFields accept the same options for validation.
<FieldError>
only takes styling for errors and is only rendered if there is an error on the associated field.
Certain <TypeField>
s have type coercion built-in, like <NumberField>
, but you can always override the coercion or, if it's not built-in, set it manually via the dataType
attribute. See dataType.
A typical React component using these helpers would look something like this Contact Us page form:
import {
Form,
Label,
TextField,
TextAreaField,
FieldError,
Submit,
} from '@redwoodjs/forms'
const ContactPage = () => {
const onSubmit = (data) => {
console.log(data)
}
return (
<Form onSubmit={onSubmit}>
<Label name="name" className="label" errorClassName="label error" />
<TextField
name="name"
className="input"
errorClassName="input error"
validation={{ required: true }}
/>
<FieldError name="name" className="error-message" />
<Label name="email" className="label" errorClassName="label error" />
<TextField
name="email"
className="input"
errorClassName="input error"
validation={{
required: true,
pattern: {
value: /[^@]+@[^\.]+\..+/,
},
}}
/>
<FieldError name="email" className="error-message" />
<Label name="message" className="label" errorClassName="label error" />
<TextAreaField
name="message"
className="input"
errorClassName="input error"
validation={{ required: true }}
/>
<FieldError name="message" className="error-message" />
<Submit className="button">Save</Submit>
</Form>
)
}
# <Form>
Any form you want Redwood to provide validation and error styling on should be surrounded by this tag. Except for the view attributes specific to validation and submission, props are passed down to the regular <form>
tag that is rendered.
<Form onSubmit={onSubmit} className="form">...</Form>
<!-- Renders: <form class="form">...</form> -->
# <Form>
Attributes
Besides the attributes listed below, any additional attributes are passed on as props to the underlying <form>
tag which is rendered.
# onSubmit
The onSubmit
prop accepts a function name or anonymous function to be called if validation is successful. This function will be called with a single object containing name/value pairs of all Redwood form helper fields in your form. Meaning if you mix <input>
and <TextField>
form fields, only <TextField>
names/values will be present.
Behind the scenes the handler given to onSubmit
is given to react-hook-form's handleSubmit
function.
# validation
The validation
prop accepts an object containing options for react-hook-form, which Redwood's <Form>
is a simple wrapper around. See the useForm for the full list of options.
The object given to validation
is forwarded to useForm
behind the scenes when creating the form. For example, to validate your form fields when the user leaves a field instead of waiting for them to click the submit button:
<Form validation={{ mode: 'onBlur' }}>
# formMethods
If you need access to the functions that useForm
gives you then you can manually call it in your component, but you'll need to provide those functions to <Form>
so that it can use those instead of calling useForm
itself and generating its own instance of them.
import { useForm } from 'react-hook-form'
const ContactPage = () => {
const formMethods = useForm()
const onSubmit = (data) => {
console.info(data)
formMethods.reset()
}
return (
<Form formMethods={formMethods} onSubmit={onSubmit}>
// ...
</Form>
)
}
# <FormError>
This helper will render a <div>
containing a "title" message and a <ul>
containing any errors reported by the server when trying to save your form data.
If an error is present the following HTML is rendered (className
and style
attributes can be passed to each element, see the *ClassName
and *Style
attribute descriptions below):
<div>
<p>
Can't create new contact:
</p>
<ul>
<li>
email is not formatted like an email address
</li>
</ul>
</div>
In this case if you provided validation for email
in the <TextField>
component itself then you wouldn't see this message at the top of your form—form validation would have caught it before it got to the GraphQL layer.
# <FormError>
Attributes
# error
An object containing server errors. Redwood expects this object to be from GraphQL listing errors in validation before submission to the server, or errors from the server when trying to mutate the data store in response to the GraphQL mutation sent across the wire.
The easiest way to get your errors in this format is give <FormError>
the error
property created by the useMutation
hook provided by @redwoodjs/web
(the body of the form has been left out to keep this code short-ish):
const CREATE_CONTACT = gql`
mutation CreateContactMutation($input: ContactInput!) {
createContact(input: $input) {
id
}
}
`
import { useMutation } from '@redwoodjs/web'
const ContactPage = (props) => {
const [create, { loading, error }] = useMutation(CREATE_CONTACT)
onSubmit = (data) => {
create({ variables: { input: data }})
}
return (
<Form onSubmit={onSubmit}>
<FormError error={error} />
// ...
</Form>
)
}
If error
contains the object that <FormError>
is expecting then the errors will be shown (in this case at the top of the form) otherwise nothing is rendered.
# wrapperStyle / wrapperClassName
style
and className
attributes given to the <div>
that surrounds the rest of the error messaging.
# titleStyle / titleClassName
style
and className
attributes given to the <p>
that contains the "title" of the error message.
# listStyle / listClassName
style
and className
attributes given to the <ul>
that surrounds each individual field error message.
# listItemStyle / listItemClassName
style
and className
attributes given to the <li>
that surround each individual field error message.
# <Label>
Generates an HTML <label>
tag but is given different style
and className
attributes depending on whether the field it is associated with (has the same name
attribute) has a validation error.
This tag can be self closing, in which case the name
becomes the text of the label:
<Label name="name" className="input" errorClassName="input error" />
<!-- Renders: <label for="name" class="input">name</label> -->
It can also have standard separate open/close tags and take text inside, in which that text will be the text of the rendered <label>
:
<Label name="name" className="input" errorClassName="input error">Your Name</Label>
<!-- Renders: <label for="name" class="input">Your Name</label> -->
# <Label>
Attributes
Besides the attributes listed below, any additional attributes are passed on as props to the underlying <label>
tag which is rendered.
# name
The name of the field that this label is connected to. This should be the same as the name
attribute on the <TextField>
or <TextAreaField>
this label is for.
# errorStyle / errorClassName
The style
and className
that should be passed to the HTML <label>
tag that is generated if the field with the same name
has a validation error.
# InputFields
Inputs are the backbone of most forms. <TextField>
renders an HTML <input type="text">
field, but is registered with react-hook-form
to provide some validation and error handling.
Note that certain InputFields handle type coercion automatically, but you can always override the coercion or, if it's not built-in, set it manually via the dataType
attribute (see dataType).
<TextField name="name" className="input" />
<!-- Renders <input type="text" name="name" class="input" /> -->
# InputFields Attributes
Besides the attributes listed below, any additional attributes are passed on as props to the underlying <input>
tag which is rendered.
# name
The name
of this field which will be used as the key in the object sent to the form's onSubmit
handler if the field passes validation. Any associated <Label>
or <FieldError>
helpers must have the same value for their name
attribute in order to be connected properly.
<TextField name="name" />
<!-- If the input contains "Rob" then the onSubmit handler receives: { name: "Rob" } -->
# errorStyle / errorClassName
The style
and className
that should be passed to the HTML <input>
tag that is generated if this field has a validation error.
# validation
Options that define how this field should be validated. The options are passed to the underlying register
function provided by react-hook-form
. The full list of possible values can be found in the react-hook-form docs (ignore the usage of ref
as that is called automaticaly for you by Redwood).
<TextField
name="email"
validation={{
required: true,
pattern: {
value: /[^@]+@[^\.]+\..+/,
},
}}
/>
# dataType
If the type to coerce the input to can’t be inferred automatically, like making a Float
from a <TextField>
for example, you can explicitly set the InputField's dataType
attribute to Boolean
, Float
, Int
, or Json
.
In the future, we'll let you pass a function to this attribute so you can do the coercion however you want.
# <TextAreaField>
# <TextAreaField>
Attributes
Besides the attributes listed below, any additional attributes are passed on as props to the underlying <textarea>
tag which is rendered.
# name
See InputFields name
# validation
See InputFields validation
# errorStyle / errorClassName
See InputFields errorStyle
# <FieldError>
Renders a <span>
containing any validation error message if the field with the same name
attribute has a validation error. Otherwise renders nothing.
<FieldError name="name" className="error-message">
<!-- Renders: <span class="error-message">name is required</span> -->
# <FieldError>
Attributes
Any attributes not listed below are passed through to the underlying <span>
tag which is rendered to contain the error message.
# name
The same as the name
of the input that this should show the error message for.
# <Submit>
Renders a <button>
tag of type "submit":
<Submit className="error-message">Save</Submit>
<!-- Renders: <button type="submit" class="button">Save</button> -->
# <Submit>
Attributes
Any attributes given to <Submit>
are passed through to the underlying <button>
tag which is rendered.