---
source_hash: "5009a04e"
title: "Chapter 3: Forms"
weight: 550
---

# Chapter 3: Forms

## Form

The `Form` component manages form submission and validation.

### Basic Syntax

```javascript
import { Form, Input, Button } from '@cap-rel/smartcommon';

function ContactForm() {
    const handleSubmit = (values) => {
        console.log(values);
        // { name: 'John', email: 'john@example.com' }
    };

    return (
        <Form onSubmit={handleSubmit}>
            <Input name="name" label="Name" required />
            <Input name="email" label="Email" type="email" required />
            <Button type="submit">Submit</Button>
        </Form>
    );
}
```

### With Initial Values

```javascript
function EditProductForm({ product }) {
    const handleSubmit = async (values) => {
        await api.private.put(`products/${product.id}`, { json: values });
    };

    return (
        <Form
            onSubmit={handleSubmit}
            defaultValues={{
                label: product.label,
                price: product.price,
                description: product.description
            }}
        >
            <Input name="label" label="Product Name" />
            <Input name="price" label="Price" type="number" />
            <Input name="description" label="Description" />
            <Button type="submit">Save</Button>
        </Form>
    );
}
```

## Input

Versatile text input field.

### Main Props

| Prop | Type | Description |
| --- | --- | --- |
| name | string | Field name (required) |
| label | string | Display label |
| type | string | 'text', 'email', 'password', 'number', 'tel' |
| placeholder | string | Placeholder text |
| required | boolean | Required field |
| disabled | boolean | Disabled field |
| error | string | Error message |

### Examples

```javascript
// Simple text
<Input name="firstName" label="First Name" />

// Email with validation
<Input name="email" label="Email" type="email" required />

// Password
<Input name="password" label="Password" type="password" />

// Number
<Input name="quantity" label="Quantity" type="number" min={0} max={100} />

// Phone
<Input name="phone" label="Phone" type="tel" />

// With placeholder
<Input
    name="search"
    placeholder="Search..."
    type="text"
/>

// Disabled
<Input name="ref" label="Reference" disabled value="PRD-001" />
```

## Textarea

Multiline text area.

```javascript
import { Textarea } from '@cap-rel/smartcommon';

<Textarea
    name="description"
    label="Description"
    rows={4}
    placeholder="Describe the product..."
/>
```

## Select

Dropdown list.

```javascript
import { Select } from '@cap-rel/smartcommon';

// Simple options
<Select
    name="category"
    label="Category"
    options={[
        { value: 'electronics', label: 'Electronics' },
        { value: 'clothing', label: 'Clothing' },
        { value: 'food', label: 'Food' }
    ]}
/>

// With empty value
<Select
    name="status"
    label="Status"
    placeholder="Select..."
    options={[
        { value: 'draft', label: 'Draft' },
        { value: 'published', label: 'Published' },
        { value: 'archived', label: 'Archived' }
    ]}
/>

// Options from API
function ProductForm() {
    const [categories, setCategories] = useState([]);

    useEffect(() => {
        api.private.get('categories').json().then(data => {
            setCategories(data.map(c => ({
                value: c.id,
                label: c.name
            })));
        });
    }, []);

    return (
        <Form>
            <Select
                name="category_id"
                label="Category"
                options={categories}
            />
        </Form>
    );
}
```

## Boolean

On/off toggle switch.

```javascript
import { Boolean } from '@cap-rel/smartcommon';

<Boolean
    name="isActive"
    label="Active Product"
/>

<Boolean
    name="notifications"
    label="Receive notifications"
    defaultValue={true}
/>
```

## Checker

Checkbox.

```javascript
import { Checker } from '@cap-rel/smartcommon';

<Checker
    name="acceptTerms"
    label="I accept the terms"
    required
/>

// Group of checkboxes
<div>
    <Checker name="options.express" label="Express delivery" />
    <Checker name="options.gift" label="Gift wrapping" />
    <Checker name="options.insurance" label="Insurance" />
</div>
```

## Calendar

Date picker.

```javascript
import { Calendar } from '@cap-rel/smartcommon';

// Simple date
<Calendar
    name="birthdate"
    label="Birth Date"
/>

// With constraints
<Calendar
    name="startDate"
    label="Start Date"
    minDate={new Date()}
    maxDate={new Date(2025, 11, 31)}
/>

// Date and time
<Calendar
    name="appointment"
    label="Appointment"
    showTime={true}
/>
```

## Timer

Time picker.

```javascript
import { Timer } from '@cap-rel/smartcommon';

<Timer
    name="startTime"
    label="Start Time"
/>

<Timer
    name="duration"
    label="Duration"
    format="HH:mm"
/>
```

## Range

Value slider.

```javascript
import { Range } from '@cap-rel/smartcommon';

<Range
    name="price"
    label="Maximum Price"
    min={0}
    max={1000}
    step={10}
/>

<Range
    name="rating"
    label="Minimum Rating"
    min={1}
    max={5}
    step={0.5}
/>
```

## ColorPicker

Color picker.

```javascript
import { ColorPicker } from '@cap-rel/smartcommon';

<ColorPicker
    name="color"
    label="Product Color"
/>
```

## FilesUploader

File upload.

```javascript
import { FilesUploader } from '@cap-rel/smartcommon';

<FilesUploader
    name="documents"
    label="Documents"
    accept=".pdf,.doc,.docx"
    multiple
    maxFiles={5}
/>
```

## PhotosUploader

Photo upload with preview.

```javascript
import { PhotosUploader } from '@cap-rel/smartcommon';

<PhotosUploader
    name="photos"
    label="Product Photos"
    maxFiles={10}
    maxSize={5 * 1024 * 1024}  // 5 MB
/>
```

## SignaturePad

Handwritten signature area.

```javascript
import { SignaturePad } from '@cap-rel/smartcommon';

<SignaturePad
    name="signature"
    label="Signature"
    width={400}
    height={200}
/>
```

## Complete Example: Product Form

```javascript
import { useEffect } from 'react';
import {
    Page,
    Block,
    Form,
    Input,
    Textarea,
    Select,
    Boolean,
    Calendar,
    PhotosUploader,
    Button
} from '@cap-rel/smartcommon';
import { useApi, useNavigation, useStates } from '@cap-rel/smartcommon';

export const ProductFormPage = ({ productId }) => {
    const api = useApi();
    const nav = useNavigation();
    const isEdit = !!productId;

    const st = useStates({
        initialStates: {
            product: null,
            categories: [],
            loading: isEdit,
            submitting: false
        }
    });

    // Load categories
    useEffect(() => {
        api.private.get('categories').json().then(data => {
            st.set('categories', data.map(c => ({
                value: c.id,
                label: c.name
            })));
        });
    }, []);

    // Load product if editing
    useEffect(() => {
        if (isEdit) {
            api.private.get(`products/${productId}`).json().then(data => {
                st.set('product', data);
                st.set('loading', false);
            });
        }
    }, [productId]);

    const handleSubmit = async (values) => {
        st.set('submitting', true);

        try {
            if (isEdit) {
                await api.private.put(`products/${productId}`, { json: values });
            } else {
                await api.private.post('products', { json: values });
            }
            nav.navigate('/products');
        } catch (err) {
            alert('Error: ' + err.message);
        } finally {
            st.set('submitting', false);
        }
    };

    if (st.get('loading')) {
        return <Page title="Loading..."><Spinner /></Page>;
    }

    return (
        <Page title={isEdit ? 'Edit Product' : 'New Product'}>
            <Block>
                <Form
                    onSubmit={handleSubmit}
                    defaultValues={st.get('product') || {
                        label: '',
                        description: '',
                        price: 0,
                        category_id: null,
                        isActive: true,
                        availableFrom: null,
                        photos: []
                    }}
                >
                    {/* Basic Information */}
                    <Input
                        name="label"
                        label="Product Name"
                        required
                    />

                    <Textarea
                        name="description"
                        label="Description"
                        rows={4}
                    />

                    <Input
                        name="price"
                        label="Price (€)"
                        type="number"
                        min={0}
                        step={0.01}
                        required
                    />

                    <Select
                        name="category_id"
                        label="Category"
                        options={st.get('categories')}
                        required
                    />

                    {/* Options */}
                    <Boolean
                        name="isActive"
                        label="Active Product"
                    />

                    <Calendar
                        name="availableFrom"
                        label="Available From"
                    />

                    {/* Photos */}
                    <PhotosUploader
                        name="photos"
                        label="Photos"
                        maxFiles={5}
                    />

                    {/* Actions */}
                    <div className="flex gap-2 mt-4">
                        <Button
                            type="button"
                            variant="outline"
                            onClick={() => nav.navigate(-1)}
                        >
                            Cancel
                        </Button>
                        <Button
                            type="submit"
                            loading={st.get('submitting')}
                        >
                            {isEdit ? 'Save' : 'Create'}
                        </Button>
                    </div>
                </Form>
            </Block>
        </Page>
    );
};
```

## Manual Validation with useForm

```javascript
import { Form, Input, Button } from '@cap-rel/smartcommon';
import { useForm } from '@cap-rel/smartcommon';

function RegisterForm() {
    const form = useForm({
        defaultValues: { email: '', password: '', confirmPassword: '' }
    });

    const handleSubmit = async (data) => {
        console.log(data);
    };

    // Manual validation via setField
    const validateEmail = (value) => {
        form.setField({
            name: 'email',
            value,
            errors: {
                required: { condition: !value },
                format: { condition: value && !value.includes('@') }
            }
        });
    };

    return (
        <Form form={form} onSubmit={handleSubmit}>
            <Input name="email" label="Email" type="email" />
            <Input name="password" label="Password" type="password" />
            <Input name="confirmPassword" label="Confirm" type="password" />
            <Button type="submit">Register</Button>
        </Form>
    );
}
```

## Key Points to Remember

1. **Form** manages submission and collects values
2. **name** is required on each field
3. **defaultValues** to pre-fill (editing)
4. **required** for mandatory fields
5. **Zod** for advanced validation

[Previous Chapter](/training/module6-smartcommon-composants/navigation) | [Back to Module](/training/module6-smartcommon-composants) | [Next Chapter: Display ->](/training/module6-smartcommon-composants/affichage)
