Skip to main content

Form layouts

Form layouts define how fields appear on a record's edit and view screens. They live in .tsx files, but they do not produce React components. Instead, a custom JSX factory compiles them into XML strings that the platform's form engine renders at runtime.

The JSX-to-XML factory

Every app's tsconfig.json includes two critical settings:

{
"jsx": "react",
"jsxFactory": "entity"
}

The entity function - implemented in api/typings/jsx-runtime.ts - is a custom JSX runtime. When TypeScript compiles a .tsx layout file, it calls entity instead of React.createElement. The return value is a plain XML string, not a virtual DOM node.

Every layout file needs two things at the top: a /** @jsx entity */ pragma and the entity import from #typings:

/** @jsx entity */
import { entity } from '#typings';

// What you write in default.tsx:
export default (
<layout>
<field name="title" />
<section caption="Details">
<field name="description" />
<field name="c_priority" />
</section>
</layout>
);

// What the compiler produces (via the entity function):
// '<field name="title" /><section caption="Details"><field name="description" /><field name="c-priority" /></section>'

The resulting XML string is stored as the layout in the compiled app schema. At runtime, the platform reads this XML and renders the form - React is never involved.

File structure

Layouts live in views/layouts/ inside the package structure:

  • default.tsx - the main form layout, used for the standard record view.
  • index.ts - exports an AppLayout map that associates layout names with their .tsx files.

You can define multiple layout files when an app needs alternative views. Each one gets an entry in the AppLayout map exported from index.ts.

Layout elements

Fields

The <field> element renders a single field on the form. Its name prop must match a field name declared in fields/index.ts:

/** @jsx entity */
import { entity } from '#typings';

export default (
<layout>
<field name="title" />
<field name="c_priority" />
<field name="c_due_date" />
</layout>
);

See Fields for the full list of field types and options.

Sections

The <section> element groups related fields under a collapsible heading:

<section caption="Billing details">
<field name="c_invoice_number" />
<field name="c_total_cost" />
<field name="c_currency" />
</section>

Sections keep complex forms organized. Users can expand or collapse them to focus on the fields they need.

Conditional rendering

Because layout files are valid TypeScript, you can use JavaScript expressions to include or exclude elements:

{showBilling && (
<section caption="Billing">
<field name="c_invoice_number" />
</section>
)}

This lets you build dynamic layouts that adapt to app configuration or context.

Props and naming conventions

Two automatic transformations happen during compilation:

  • CamelCase to kebab-case - a prop written as camelCase in TSX becomes camel-case in the output XML. For example, c_priority stays as-is because underscores are not affected, but a hypothetical dataSource prop would become data-source.
  • HTML escaping - all prop values are escaped so that characters like <, >, and & do not break the XML output.

The name prop on <field> always references a field name from Fields. Keep field names consistent between fields/index.ts and your layout files.

Common mistake - treating layouts as React

The single most frequent error is writing React code inside a .tsx layout file. Because the file extension is .tsx and the syntax looks like JSX, developers assume they can use:

  • React hooks (useState, useEffect)
  • Component state and lifecycle methods
  • React context or portals

None of these work. The entity factory returns a string, not a React element tree. If you need runtime UI behavior - such as showing or hiding fields based on the current record state - use View logic hooks instead. See Common mistakes for more examples.

Quick reference

ElementPurposeKey prop
<field>Render a single fieldname - field name from fields/index.ts
<section>Collapsible group of fieldscaption - section heading text
  • Fields - field types and options that <field> elements reference.
  • View logic - runtime visibility, requiredness, and read-only rules.
  • Package structure - where layout files sit in the app directory.