UI Lab

    Form Variants

    Different form layouts and patterns — switch stack and implementation mode, then pick a variant. FormConfig with React Hook Form, TanStack Form, or useActionState.

    Build your own
    Job Application

    Senior Software Engineer

    Join our engineering team and build amazing products

    Personal Information

    Application Details

    Click to upload or drag and drop

    Submitted data

    Waiting for a submit…

    Submit the form above to see the validated payload rendered here.

    Source Code

    Install & set up

    Everything this form needs: 6 generated files to copy and 26 shared engine files the CLI can install for you.

    1

    Form stack

    Which form library the generated fields are wired to. Changes the code below and the live preview above.

    2

    Implementation mode

    JSON Config reads a formConfig.ts at runtime through a generic renderer. Static JSX hand-unrolls each field instead — no formConfig.ts, no runtime dispatcher.

    3

    Choose how data is fetched

    Two independent choices. The default adds no dependency at all — the command below and the code both follow whatever you pick.

    HTTP client used by services.ts

    Where results live used by hooks.ts

    Adds no extra packages.

    4

    Install it with the CLI

    recommended

    Installs every file below and its packages in one command. The steps after this are only for doing it by hand.

    npx afnoui add forms/forms-job-application
    Writes to 3 places
    5

    Or install the packages yourself

    Only needed if you copied the files by hand instead of running the command above.

    Runtime dependencies

    npm install @hookform/resolvers date-fns react-hook-form zod

    Dev dependencies

    npm install -D @types/react @types/react-dom typescript

    Generated files

    Generated files are yours to copy and edit; shared engine files are installed once and reused.

    Generated per form(6)

    Shared engine — copy once(26)

    Generated per form

    Your form's JSON configuration — defines structure, fields, validation, and layout.

    forms/formConfig.ts
    forms/formConfig.ts
    import { FormConfig } from "../components/forms/types/types";
    
    export const formConfig: FormConfig = {
      "id": "job-application-form",
      "title": "Senior Software Engineer",
      "description": "Join our engineering team and build amazing products",
      "submitLabel": "Submit Application",
      "showReset": false,
      "layout": "single",
      "sections": [
        {
          "id": "personal-info",
          "title": "Personal Information",
          "columns": 2,
          "fields": [
            {
              "type": "text",
              "name": "firstName",
              "label": "First Name",
              "placeholder": "John",
              "required": true
            },
            {
              "type": "text",
              "name": "lastName",
              "label": "Last Name",
              "placeholder": "Doe",
              "required": true
            },
            {
              "type": "email",
              "name": "email",
              "label": "Email",
              "placeholder": "john@example.com",
              "required": true
            },
            {
              "type": "tel",
              "name": "phone",
              "label": "Phone",
              "placeholder": "+1 (555) 000-0000"
            },
            {
              "type": "url",
              "name": "linkedin",
              "label": "LinkedIn Profile",
              "placeholder": "https://linkedin.com/in/johndoe"
            },
            {
              "type": "select",
              "name": "experience",
              "label": "Years of Experience",
              "options": [
                {
                  "label": "0-2 years",
                  "value": "0-2"
                },
                {
                  "label": "3-5 years",
                  "value": "3-5"
                },
                {
                  "label": "5-8 years",
                  "value": "5-8"
                },
                {
                  "label": "8+ years",
                  "value": "8+"
                }
              ]
            }
          ]
        },
        {
          "id": "application-details",
          "title": "Application Details",
          "columns": 1,
          "fields": [
            {
              "type": "file",
              "name": "resume",
              "label": "Resume/CV",
              "accept": ".pdf,.doc,.docx",
              "required": true
            },
            {
              "type": "textarea",
              "name": "coverLetter",
              "label": "Why do you want to join us?",
              "placeholder": "Tell us about yourself...",
              "rows": 4
            }
          ]
        }
      ]
    };