

<Tabs items="[&#x22;Preview&#x22;, &#x22;Code&#x22;]">
  <Tab value="Preview">
    <Preview name="SingleGroupedLayoutExample" />
  </Tab>

  <Tab value="Code">
    ```tsx
    "use client";

    import { z } from "zod";
    import { FormBuilder } from "@tilt-legal/cubitt-components/composites";

    const schema = z.object({
      title: z.string().min(1, "Required"),
      code: z.string().optional(),
      description: z.string().optional(),
      practiceArea: z.string(),
      priority: z.enum(["low", "normal", "high"]),
      confidential: z.boolean().default(false),
    });

    const formDefs = [
      {
        kind: "group",
        title: "Matter Basics",
        children: [
          {
            kind: "field",
            name: "title",
            label: "Title",
            component: "text",
            size: "half",
          },
          {
            kind: "field",
            name: "code",
            label: "Matter Code",
            component: "text",
            size: "half",
          },
          {
            kind: "field",
            name: "description",
            label: "Description",
            component: "textarea",
            size: "full",
          },
        ],
      },
      {
        kind: "group",
        title: "Classification",
        children: [
          {
            kind: "field",
            name: "practiceArea",
            label: "Practice Area",
            component: "select",
            options: [
              { label: "Corporate", value: "corp" },
              { label: "Litigation", value: "lit" },
              { label: "IP", value: "ip" },
            ],
          },
          {
            kind: "field",
            name: "priority",
            label: "Priority",
            component: "radio",
            options: [
              { id: "low", value: "low", label: "Low" },
              { id: "normal", value: "normal", label: "Normal" },
              { id: "high", value: "high", label: "High" },
            ],
          },
          {
            kind: "field",
            name: "confidential",
            label: "Confidential",
            component: "switch",
          },
        ],
      },
    ] as const satisfies FormDefs;

    export default function GroupedForm() {
      return (
        <FormBuilder.Single
          schema={schema}
          formDefs={formDefs}
          defaultValues={{
            title: "",
            code: "",
            description: "",
            practiceArea: "",
            priority: "normal",
            confidential: false,
          }}
          submitLabel="Save"
          onSubmit={async (values) => console.log(values)}
        />
      );
    }
    ```
  </Tab>
</Tabs>

## How It Works [#how-it-works]

1. **Wrap fields in group nodes** – Use `kind: "group"` with a `title` and `children` array
2. **Use size hints** – Set `size: "half"` or `size: "full"` to control field widths
3. **Mix component types** – Text, textarea, select, radio, and switch all work together

<Callout type="info">
  See [Group Nodes](/composites/form-builder/form-defs#group-nodes) for all
  available group properties.
</Callout>
