Blank white background with no objects or features visible.

TrueFoundry anuncia la adquisición de Seldon AI, ampliando su plataforma de control para IA empresarial. Lea el informe completo →

Schema-Driven Forms in React: Building with TrueFoundry FormBuilder

Por Shubham Kumar Singh

Published: July 4, 2026

If you’ve used TrueFoundry to deploy a service, create a cluster, configure an LLM model, or manage secrets, you’ve interacted with forms that look like normal UI, but are built very differently from typical web forms.

⚡ TL;DR

TrueFoundry’s FormBuilder is a schema-driven form system that uses structured JSON to automatically render dynamic React inputs, groups, and validation logic. This architecture ensures consistent behavior across complex resource configurations, simplifies nested state management using react-hook-form, and allows for rapid development of domain-specific UIs. TrueFoundry does not hand-code every field on every screen. Instead, it uses a schema-driven form system called FormBuilder. A form is defined as structured JSON (the schema). The UI reads that schema and renders the right inputs, groups, validations, and conditional fields automatically.

This post explains how that works, in four parts:
  • What a form schema looks like
  • How fields are mapped to UI components and rendered
  • How form state is managed
  • How validation works

Why TrueFoundry uses schema-driven forms

TrueFoundry forms often represent manifests - YAML/JSON objects you can also apply with the CLI (tfy apply -f ...). The same object might be edited in the UI, downloaded as YAML, or submitted to the API.

A schema-driven approach gives TrueFoundry:

  • One source of truth for form structure (loaded from the backend per resource type).
  • Consistent behavior across deployments, clusters, policies, models, secrets, settings forms, or any other form in the platform.
  • Nested and conditional fields without rewriting form logic on every screen.
  • Domain-specific widgets (cluster picker, secret selector, resource limits) plugged into a shared runtime.

The mental model: the schema describes the shape of the data and how to edit it; FormBuilder turns that description into a working form.

1. Form schema:

A form schema is an array of field definitions. Each field is an object with a few important properties:

Property Purpose
jsonKey Where this field lives in the submitted object (supports nesting, e.g. image.build_source.type).
label What the user sees.
uiType Which UI component to render (text input, select, group, custom widget, etc.).
sort Display order.
validate Required, min/max, pattern, defaults, custom validators.
conditions Show/hide or enable/disable based on other fields.
subParameters Child fields for groups and repeated sections.
uiProps Extra options passed to the component (search, table view, etc.).

Here is a simplified generic example - not a real TrueFoundry schema, but close to how the product thinks about configuration:

[
  {
    "sort": 1,
    "jsonKey": "name",
    "label": "Service Name",
    "uiType": "Input",
    "validate": { "required": true, "pattern": "^[a-z0-9-]+$" }
  },
  {
    "sort": 2,
    "jsonKey": "image",
    "label": "Image",
    "uiType": "Group",
    "subParameters": [
      {
        "jsonKey": "type",
        "label": "Source",
        "uiType": "Radio",
        "validate": {
          "required": true,
          "defaultValue": "build",
          "options": [
            { "label": "Build", "value": "build" },
            { "label": "Existing image", "value": "existing" }
          ]
        }
      },
      {
        "jsonKey": "uri",
        "label": "Image URI",
        "uiType": "Input",
        "conditions": [
 		{ "jsonKey": "image.type", "op": "==", "value": "existing"  }
  ],
        "validate": { "required": true }
      }
    ]
  }
]

Resulting manifest/config on submit:

{
  "name": "my-service",
  "image": { "type": "existing", "uri": "registry.io/app:v1" }
}

2. How components are mapped and fields are rendered

Rendering happens in a small pipeline, the flow is:

FormBuilder walks the schema tree and picks a React component per node based on uiType.

Component types:

  • Basic: Input, Select, Radio, Switch, Number
  • Structural: Group (section), Structs (repeatable list), KV / ENV (key-value)
  • Domain Specific: ClusterSelect, SecretSelect, Resources, ModelSelect, PermissionsMatrix, MCP fields, and more

Conditions: If image.type !== "existing", the URI field never mounts. With shouldUnregister: true, it also leaves form state, so hidden values cannot leak into the payload.

Mapping logic in code:

// FormComponentMap
const ComponentType = FormComponents[schema.uiType]
const CustomComp = CustomComponentsMap?.[schema.uiType]

if (!enabledByCondition) return null

return CustomComp
  ? <CustomComp schema={schema} />
  : <ComponentType schema={schema} />

3. How form state is handled

FormBuilder uses react-hook-form as its state engine. That choice matters for how the product behaves.

Initialization/Component Usage - create & edit:

<FormBuilder
  schema={schema}
  defaultValues={existingManifest}   // edit: pre-fill; create: empty/template
  onSubmit={(manifest) => createOrUpdate({ manifest })}
/>

Form setup:

const methods = useForm({
  mode: 'onChange',          // validate as user types
  defaultValues,
  shouldUnregister: true,    // hidden fields drop out of state
})

Field registration - each input binds to its path:

// Inside a text field component
const { register } = useFormContext()

<input
  {...register(schema.jsonKey, registerProps)}
  defaultValue={defaultValue}
/>

Extra context - specific form pass runtime data separate from field values:

<FormBuilder
  schema={schema}
  extraContext={{
    workspace,
    cluster,
    serviceAccountOptions,  // dynamic dropdown options
    dataTestPrefix: 'create-cluster',
  }}
/>

Single object, nested paths:

All field values live in one form object. Each field registers under its full jsonKey path:

  • name → top-level string
  • image.type → nested value
  • ports.0.container_port → first item in an array

When you edit a field, you are mutating this shared object. On submit, FormBuilder reads the whole object and passes it to the form’s handler (which usually calls the TrueFoundry API or produces YAML).

Defaults and edit mode:

When opening a form to create something, defaultValues may be empty or come from a template.

When editing, defaultValues is typically the existing manifest. The form fields pre-fill from that object. Some fields are marked immutable in edit mode (e.g. resource name) so they render read-only.

Hidden fields are removed from state:

TrueFoundry forms use shouldUnregister: true. That means:

  • If a field is hidden by a condition, it is unregistered from form state
  • Its value does not leak into the submitted payload

This is important for conditional forms: you only submit what the user could actually see and edit.

4. How validation works

Validation in TrueFoundry forms happens at two layers.

Layer 1: Schema validation (declarative)

Each field’s validate block can specify:

  • required
  • min / max (allowed range of integer value)
  • minLength / maxLength (string or array length)
  • pattern (regex) with custom message
  • defaultValue
  • immutable (read-only in edit mode)

These rules are converted into react-hook-form validation rules. Errors are shown inline next to the field. Validation runs on change (mode: 'onChange'), so users get feedback as they type, not only on submit.

Layer 2: Custom and async validation

Schemas can also attach a custom validate function, commonly used for:

  • Name uniqueness (“A entity with this name already exists”)
  • API-backed checks before submit
  • Cross-field rules inside a custom component
  • Screens attach these at runtime with helpers like “attach validation to field name”. The UI shows a spinner while async validation runs (e.g. debounced name check).
useAttachValidation(schema, {
  name: async (name) => {
    const taken = await checkNameExists(name)
    return taken ? 'Name already exists' : true
  },
})

Putting it together: what you experience as a user

When you open “Create Cluster”, “Deploy Service”, “Add Model”, or “Manage Secrets”:

  • TrueFoundry loads (or builds) a schema for that resource
  • FormBuilder renders each schema node as the desired input component
  • Your edits update a single nested form object
  • Validation runs continuously and again on submit
  • The final object is a manifest - the same shape you’d use in YAML or the CLI

That is why TrueFoundry can support very complex configuration UIs without every screen being a one-off form: the complexity lives in the schema and a library of field components, orchestrated by one shared runtime.

Try now.

One gateway for all your models, MCP servers, and agents.
No credit card needed.

Inscríbase
Tabla de contenido

Controle, implemente y rastree la IA en su propia infraestructura

Reserva 30 minutos con nuestro Experto en IA

Reserve una demostración

La forma más rápida de crear, gobernar y escalar su IA

Demo del libro
Summarize with
ChatGPT logo by OpenAI
Perplexity AI logo
Blurry red snowflake on white background, symmetrical frosty design with soft edges and abstract shape.

Descubra más

No se ha encontrado ningún artículo.
August 14, 2026
|
5 minutos de lectura

The Human Gate: Designing MCP Tool Approvals at the Gateway Boundary

No se ha encontrado ningún artículo.
August 13, 2026
|
5 minutos de lectura

AI Coding Agent Pricing: How to Choose the Right Plan

No se ha encontrado ningún artículo.
 What is an LLM Gateway
August 12, 2026
|
5 minutos de lectura

¿Qué es un LLM Gateway? Una guía completa

Ingeniería y producto
openrouter vs litellm
August 12, 2026
|
5 minutos de lectura

LitellM vs OpenRouter: ¿Cuál es el adecuado para usted?

comparación
No se ha encontrado ningún artículo.

Blogs recientes

Black left pointing arrow symbol on white background, directional indicator.
Black left pointing arrow symbol on white background, directional indicator.

Preguntas frecuentes

¿Por qué elegir un enfoque impulsado por esquemas en lugar de codificar formularios manualmente?

Los formularios impulsados por esquemas proporcionan una única fuente de verdad para sus manifiestos de configuración. Garantizan un comportamiento uniforme de la interfaz de usuario, permiten lógica anidada/condicional sin código repetido y posibilitan que el backend defina la estructura del formulario de forma dinámica.

¿Cómo funciona la validación en FormBuilder?

La validación se realiza en dos capas: validación declarativa de esquema (utilizando reglas como obligatorio, patrón o mín/máx) y validación personalizada/asíncrona para comprobaciones respaldadas por API, como la verificación de nombres de recursos únicos.

¿Puedo integrar esto con bibliotecas de React existentes?

Sí. El FormBuilder de TrueFoundry utiliza react-hook-form como su motor de estado principal, lo que lo hace compatible con los patrones estándar de React y fácil de extender con componentes personalizados.

Realice un recorrido rápido por el producto
Comience el recorrido por el producto
Visita guiada por el producto