# 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[​](#the-jsx-to-xml-factory "Direct link to The JSX-to-XML factory")

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

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

The `entity` function 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[​](#file-structure "Direct link to File structure")

Layouts live in `views/layouts/` inside the [package structure](/developer-guide/app-architecture/package-structure.md):

* `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[​](#layout-elements "Direct link to Layout elements")

### Fields[​](#fields "Direct link to 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](/developer-guide/building-blocks/fields-and-field-options.md) for the full list of field types and options.

### Sections[​](#sections "Direct link to 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[​](#conditional-rendering "Direct link to 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[​](#props-and-naming-conventions "Direct link to 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](/developer-guide/building-blocks/fields-and-field-options.md). Keep field names consistent between `fields/index.ts` and your layout files.

## Common mistake - treating layouts as React[​](#common-mistake---treating-layouts-as-react "Direct link to 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](/developer-guide/building-blocks/view-logic.md) hooks instead. See [Common mistakes](/developer-guide/how-to/common-mistakes.md) for more examples.

## CSS best practices[​](#css-best-practices "Direct link to CSS best practices")

* Use `<style jsx>` inside the layout TSX file - it scopes styles to the app's form
* Prefix all custom class names with the app alias (e.g., `.crm-totals`, `.itsm-header`) to avoid collisions with platform CSS
* Avoid changing `font-family`, `font-size`, or other typography on `body`, `.form-container`, or other broad selectors - platform CSS loads after custom styles and overrides them, causing a visible flash
* For one-off style overrides, inline styles on elements are safest
* Custom layouts support Angular template expressions (`ngBindHtml`) for dynamic HTML content bound to `ComindView.ui` properties

Example of properly scoped CSS in a layout:

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

export default (
  <layout>
    <style jsx>{`
      .crm-summary { padding: 12px; background: #f8f9fa; border-radius: 4px; }
      .crm-summary-value { font-size: 18px; font-weight: 600; color: #1976d2; }
    `}</style>
    <div class="crm-summary">
      <div class="crm-summary-value" ngBindHtml="ui.totalAmount"></div>
    </div>
  </layout>
);
```

## Quick reference[​](#quick-reference "Direct link to Quick reference")

| Element     | Purpose                     | Key prop                                   |
| ----------- | --------------------------- | ------------------------------------------ |
| `<field>`   | Render a single field       | `name` - field name from `fields/index.ts` |
| `<section>` | Collapsible group of fields | `caption` - section heading text           |

## What to read next[​](#what-to-read-next "Direct link to What to read next")

* [Fields](/developer-guide/building-blocks/fields-and-field-options.md) - field types and options that `<field>` elements reference.
* [View logic](/developer-guide/building-blocks/view-logic.md) - runtime visibility, requiredness, and read-only rules.
* [Package structure](/developer-guide/app-architecture/package-structure.md) - where layout files sit in the app directory.
* [How to display links in form](/developer-guide/how-to/standard/how-to-display-links-in-form.md) - three methods for rendering clickable links in layouts.
* [How to display external images in form and list](/developer-guide/how-to/standard/how-to-display-external-images-in-form-and-list.md) - techniques for showing URL-based images in forms and grids.
