# Grouped form

Use a shared outer grid for peer groups, with the same surface padding and field
spacing. Each group owns its title and reading order. Two short fields stack
inside each group; the next row reuses the same tracks instead of inventing a
new four-column or uneven grid. This recipe illustrates workspace preferences,
not an invoice-specific screen or a universal two-column requirement.

Choose the number of tracks from the task and declared viewport. A long-address
group may span the row; a short field does not need its own column. Keep related
fields together in DOM order, including when an optional field disappears.
Use Grid, Fieldset, Surface and Field rather than recreating their recipes.

Import the shared stylesheet once and render inside FloodRoot. onApply receives
native FormData in the host; this recipe implements no persistence or permissions.
Those limits belong here in documentation, not as repeated captions in the form.

## Source

```tsx
"use client";
import type {FormEvent} from 'react';
import {Button,Field,Fieldset,Grid,Input,Select,Stack,Surface} from '@flood-md/react';

/** Shared outer tracks; groups retain their own reading order and field ownership. */
export function GroupedForm({showBillingEmail=true,onApply}:{showBillingEmail?:boolean;onApply?:(values:FormData)=>void}) {
  function submit(event:FormEvent<HTMLFormElement>){event.preventDefault();onApply?.(new FormData(event.currentTarget));}
  return <form aria-label="Workspace settings" onSubmit={submit}>
    <Stack gap="8">
      <Grid columns={2} gap="6">
        <Surface padding="6"><Fieldset legendSize="section" legend="Identity"><Stack gap="6">
          <Field label="Workspace name" required>{props=><Input {...props} name="workspace" required />}</Field>
          <Field label="Reference">{props=><Input {...props} name="reference" />}</Field>
        </Stack></Fieldset></Surface>
        <Surface padding="6"><Fieldset legendSize="section" legend="Locale"><Stack gap="6">
          <Field label="Language">{props=><Select {...props} name="language" defaultValue="en"><option value="en">English</option><option value="ru">Русский</option></Select>}</Field>
          <Field label="Time zone">{props=><Select {...props} name="timezone" defaultValue="UTC"><option value="UTC">UTC</option><option value="Asia/Almaty">Almaty</option></Select>}</Field>
        </Stack></Fieldset></Surface>
        <Surface padding="6"><Fieldset legendSize="section" legend="Primary contact"><Stack gap="6">
          <Field label="Contact name">{props=><Input {...props} name="contact" />}</Field>
          <Field label="Contact email">{props=><Input {...props} name="contactEmail" type="email" />}</Field>
        </Stack></Fieldset></Surface>
        <Surface padding="6"><Fieldset legendSize="section" legend="Billing contact"><Stack gap="6">
          <Field label="Billing name">{props=><Input {...props} name="billing" />}</Field>
          {showBillingEmail&&<Field label="Billing email">{props=><Input {...props} name="billingEmail" type="email" />}</Field>}
        </Stack></Fieldset></Surface>
      </Grid>
      <Button type="submit">Apply settings</Button>
    </Stack>
  </form>;
}
```

## Review

Compare left/right edges and gutters in both rows, label/control associations,
native required submission and omitted optional content. Inspect long labels and
enlarged text at the host's declared widths. Do not judge a form by zero page
overflow alone. Read the [forms workflow](/agent/references/flood-forms/SKILL.md)
and [content workflow](/agent/references/flood-interface-content/SKILL.md) before
adapting it. A useful form does not need a helper paragraph under every title.

Independent sections use Fieldset legendSize="section" and keep one shared outer
Grid across peer groups. Field labels retain the compact inner gap; Stack owns
row separation. The hierarchy workflow explains why section titles and choice
captions are different roles.
