How to build a form using Marigold components?
How to build a form using components from Marigold?
I'll help you understand how to build a form using components from Marigold. Let me explore the repository structure first to find form-related components and documentation.
Great! I can see there's comprehensive documentation about forms. Let me look at the Form implementation guide and form components:
Now let me check what form components are available:
Let me also look at some practical examples in the codebase:
Let me find the actual demo files:
Perfect! Let me check a few practical examples:
Perfect! Now let me get one more example with validation:
Excellent! Now I have enough information to provide a comprehensive answer. Let me create a detailed summary:
##How to Build a Form Using Marigold Components
Here's a comprehensive guide based on the Marigold documentation:
###Basic Form Structure
Marigold provides a <Form> component that acts as a container for your form fields. Here's the simplest approach:
import { Form, TextField, Button, Stack } from '@marigold/components';
export default function MyForm() {
return (
<Form onSubmit={(e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data = Object.fromEntries(formData);
console.log(data);
}}>
<Stack space={4}>
<TextField name="email" label="Email" />
<TextField name="password" label="Password" type="password" />
<Button type="submit">Submit</Button>
</Stack>
</Form>
);
}
###Available Form Components
Marigold offers a full suite of form components:
- Text Input:
TextField,TextArea,SearchField - Selection:
Select,Checkbox,Radio,Switch - Multi-Selection:
Multiselect,Autocomplete,Combobox - Numbers & Dates:
NumberField,DateField,DatePicker,TimeField,Calendar,Slider - File Input:
FileField - Container:
Form,Label
###Using Uncontrolled Components (Simple Forms)
For simple forms without complex validation, use uncontrolled components with the browser's FormData API:
const [state, formAction] = useActionState<FormState, FormData>(
(_previousState: FormState, formData: FormData) => {
return { promoCode: formData.get('promocode') };
},
INITIAL_STATE
);
return (
<Form action={formAction}>
<Stack space={1} alignX="left">
<TextField label="Promo Code" name="promocode" width={44} />
<Button variant="primary" size="small" type="submit">
Submit
</Button>
</Stack>
</Form>
);
###Form Field Anatomy
Each form field should include:
- Label: Describes what the user should enter
- Input Control: The actual input element
- Description (optional): Helper text providing additional context
- Error Message (optional): Displayed when validation fails
<TextField
name="email"
label="Email Address"
description="We'll never share your email"
error={hasError}
errorMessage="Please enter a valid email"
required
/>
###Validation Approaches
####1. With React Hook Form (Recommended for Complex Forms)
import { Controller, useForm } from 'react-hook-form';
export default function ComplexForm() {
const { control, handleSubmit, formState: { isValid } } = useForm({
mode: 'onChange',
defaultValues: {
firstName: '',
email: '',
},
});
return (
<form onSubmit={handleSubmit((data) => console.log(data))}>
<Stack space={4}>
<Controller
name="firstName"
control={control}
rules={{ required: 'First name is required' }}
render={({ field, fieldState: { error } }) => (
<TextField
{...field}
label="First Name"
required
error={!!error}
errorMessage={error?.message}
/>
)}
/>
<Button type="submit" disabled={!isValid}>Submit</Button>
</Stack>
</form>
);
}
####2. With Zod Schema Validation
import { z } from 'zod';
export default function FormWithZod() {
const schema = z.object({
email: z.string().email('Invalid email'),
name: z.string().min(1, 'Name required'),
});
const [errors, setErrors] = useState<string[]>([]);
const handleSubmit: FormEventHandler<HTMLFormElement> = (e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
const data = Object.fromEntries(formData);
const validation = schema.safeParse(data);
if (!validation.success) {
setErrors(validation.error.issues.map(issue => issue.path.toString()));
} else {
// Submit form
}
};
return (
<form onSubmit={handleSubmit}>
<TextField
name="email"
label="Email"
error={errors.includes('email')}
errorMessage="Invalid email"
/>
<Button type="submit">Submit</Button>
</form>
);
}
###Error Handling
The <Form> component automatically handles validation errors from servers:
<Form validationErrors={serverErrors}>
<TextField name="email" label="Email" />
</Form>
When validationErrors is set, errors appear below fields and are automatically cleared when users modify the field.
###Layout Components for Forms
Use layout components to structure your forms:
<Stack space={4}> {/* Vertical stacking */}
<Columns columns={[2]}> {/* 2-column grid */}
<TextField label="First Name" />
<TextField label="Last Name" />
</Columns>
<Inset> {/* Add spacing around content */}
<TextField label="Email" />
</Inset>
</Stack>
###Key Takeaways
- Always include a
nameattribute on form fields for data submission - Use labels for accessibility and clarity
- Choose controlled (React Hook Form) or uncontrolled approaches based on complexity
- Validate early and often with clear error messages
- Test accessibility with screen readers and keyboard navigation
- Use layout components like
Stack,Columns, andInsetfor consistent spacing
For more detailed examples and patterns, check the Form Implementation Guide and Form Fields documentation in the Marigold docs.
END OF POST
Claude Haiku 4.5