Get Started
Introduction
Components
Accordion
Badge
Button
Card
Checkbox
Command
Dialog
Dropdown Menu
Input
Select
Switch
Table
Tabs
Toast
Tooltip
Forms
Introduction
Validation
Field Arrays

Form Builder

A signal-driven form builder with dynamic field type switching, nested groups, conditional visibility, and live preview.

#Preview

Form Builder

6 fields3 required

Builder

Show when:
Show when:
Show when:
Show when:
Show when:
Show when:

Preview

1"use client"23import { createSignal, createMemo } from '@barefootjs/client'4import { Button } from '@/components/ui/button'5import { Input } from '@/components/ui/input'6import { NativeSelect, NativeSelectOption } from '@/components/ui/native-select'7import { Checkbox } from '@/components/ui/checkbox'89type FieldType = 'text' | 'select' | 'checkbox' | 'group'1011type FieldSchema = {12  id: number13  type: FieldType14  label: string15  required: boolean16  options: string17  visibleWhen: string18  children: ChildField[]19}2021function FormBuilder() {22  const [fields, setFields] = createSignal<FieldSchema[]>(initialFields)23  const [previewValues, setPreviewValues] = createSignal<Record<string, string>>({})2425  const visibleFieldsInPreview = createMemo(() => {26    const vals = previewValues()27    return fields().filter(f => {28      if (!f.visibleWhen) return true29      return vals[f.visibleWhen]?.trim().length > 030    })31  })3233  // Heterogeneous loop — key compiler stress test34  return (35    <div className="grid grid-cols-2 gap-6">36      {/* Builder: body varies by field.type */}37      <div>38        {fields().map(field => (39          <div key={field.id}>40            <NativeSelect41              value={field.type}42              onChange={(e) => updateField(field.id, { type: e.target.value as FieldType })}43            >44              <NativeSelectOption value="text">Text</NativeSelectOption>45              <NativeSelectOption value="select">Select</NativeSelectOption>46              <NativeSelectOption value="checkbox">Checkbox</NativeSelectOption>47              <NativeSelectOption value="group">Group</NativeSelectOption>48            </NativeSelect>49            <Input value={field.label} onInput={(e) => updateField(field.id, { label: e.target.value })} />5051            {/* Type-specific options — heterogeneous body */}52            {field.type === 'select' ? (53              <Input value={field.options} onInput={(e) => updateField(field.id, { options: e.target.value })} />54            ) : null}55            {field.type === 'group' ? (56              <div>57                {field.children.map(child => (58                  <Input key={child.id} value={child.label} />59                ))}60              </div>61            ) : null}62          </div>63        ))}64      </div>6566      {/* Preview: conditional visibility + heterogeneous rendering */}67      <div>68        {visibleFieldsInPreview().map(field => (69          <div key={field.id}>70            {field.type === 'text' ? (71              <Input placeholder={field.label} onInput={(e) => setPreviewValues(p => ({...p, [field.label]: e.target.value}))} />72            ) : null}73            {field.type === 'select' ? (74              <NativeSelect>75                {field.options.split(',').map(opt => (76                  <NativeSelectOption key={opt.trim()} value={opt.trim()}>{opt.trim()}</NativeSelectOption>77                ))}78              </NativeSelect>79            ) : null}80            {field.type === 'checkbox' ? <Checkbox /> : null}81            {field.type === 'group' ? (82              <div>83                {field.children.map(child => (84                  <Input key={child.id} placeholder={child.label} />85                ))}86              </div>87            ) : null}88          </div>89        ))}90      </div>91    </div>92  )93}

#Features

Heterogeneous Loop

Both the builder and preview render fields().map() where the JSX body varies completely by field.type. This is the primary compiler stress test: a loop whose items require structurally different output.

Schema Change → Loop Rebuild

Switching a field’s type via the dropdown mutates the schema signal, forcing the loop to reconstruct that slot’s entire subtree — text options disappear, select options appear, group children render.

Nested Field Groups

Group fields contain a children array rendered as a nested loop in both the builder (child editors) and the preview (child inputs). Tests nested loop rendering with heterogeneous child types.

Conditional Visibility

Each field can declare a visibleWhen condition — the label of another field that must be non-empty. The visibleFieldsInPreview memo filters the schema reactively, and the preview only renders matching fields.

Text
Textarea
Select
Checkbox
Group
Text
Textarea
Select
Checkbox
Group
Text
Textarea
Select
Checkbox
Group
Text
Textarea
Select
Checkbox
Group
Text
Checkbox
Select
Text
Checkbox
Select
Text
Checkbox
Select
Text
Textarea
Select
Checkbox
Group
Text
Textarea
Select
Checkbox
Group
USA
Canada
UK
Australia