Repeated field names
There are some situations where you might want to have multiple inputs with the same name.
A common use-case for this would be groups of checkboxes.
The way this is handled in remix-validated-form
,
is that any fields that are submitted with the same name will be grouped together as an array.
If only one field is submitted for a given name, then it will be treated as a single value.
Example:
const inputs = (
<>
<input
type="checkbox"
name="myCheckboxGroup"
value="value1"
/>
<input
type="checkbox"
name="myCheckboxGroup"
value="value2"
/>
</>
);
// If both are checked
const result = {
myCheckboxGroup: ["value1", "value2"],
};
// If only one is checked
const result = {
myCheckboxGroup: "value1",
};
Validating
When constructing your validation schema, you need to keep in mind that
the value could be an array or a single value.
The easiest way to handle this is with repeatable
from zod-form-data.
import { zfd } from "zod-form-data";
export const validator = withZod(
z.object({ likes: zfd.repeatable() })
);
Considerations for your components
One thing to keep in mind when using repeated field names,
is that all of the inputs will receive the same error
prop.
For the most common use-cases (checkbox groups and radio groups),
you probably only need to display the error once for the whole group.
If you do need to display an error for each input,
you're probably better off naming your inputs with the array syntax
(e.g. myField[0]
).
Here's one possible implementation of this:
export type CheckboxProps = {
label: string;
name: string;
value?: string;
};
export const Checkbox: FC<CheckboxProps> = ({
label,
name,
value,
}) => {
const { getInputProps } = useField(name);
return (
<div>
<label>
{label}
<input
{...getInputProps({ type: "checkbox", value })}
/>
</label>
</div>
);
};
export type CheckboxGroupProps = {
label: string;
name: string;
};
export const CheckboxGroup: FC<CheckboxGroupProps> = ({
label,
name,
children,
}) => {
const { error } = useField(name);
return (
<fieldset>
<legend>{label}</legend>
{children}
{error && <p className="myErrorClass">{error}</p>}
</fieldset>
);
};