# Fields and field options

Fields define what data an app stores and how that data appears in the UI. Every app exports an `AppField[]` array from `fields/index.ts`. The engine reads this array at startup and builds the schema, form controls, and validation rules from it.

This page covers data types, the type system, field options, calculated fields, and naming conventions.

## Data types[​](#data-types "Direct link to Data types")

Each field has a `type` property drawn from one of three unions.

**`DataType`** - the primary data type:

`text` · `lookup` · `lookupMulti` · `appsLookup` · `linkto` · `linkslist` · `fileslist` · `peoplelist` · `date` · `datetime` · `person` · `bool` · `number` · `object`

**`TextType`** - sub-type used when `type` is `'text'`:

`string` · `keyword` · `text` · `richtext`

**`NumberType`** - sub-type used when `type` is `'number'`:

`unknown` · `float` · `integer`

**`CalcType`** - for computed fields (see [Calculated fields](#calculated-fields) below):

`calcfield` · `rollup` · `datarollup` · `treerollup` · `shadow` · `tablecalcfield`

A field that stores a single-line string uses `type: 'text'` with a text sub-type of `'string'`. A field that stores a currency amount uses `type: 'number'` with a number sub-type of `'float'` and a `decimal_places` option.

## Type system[​](#type-system "Direct link to Type system")

The engine generates TypeScript types from field definitions so that record access is fully typed:

```
const { entity, entityOld, records } = makeEntity(fields, actions);
// entity.title, entity.state - fully typed based on field definitions
```

Key type utilities:

* `FieldName<Entity>` - all accessible field names
* `EditableFieldName<Entity>` - writable fields only
* `fieldName__resolved` - expands to `{ caption, position }` for lookup fields
* `fieldName__list` - expands to `Array<ListEntry>` for list-type fields

Use these utilities in [actions](/developer-guide/building-blocks/actions.md) and [view logic](/developer-guide/building-blocks/view-logic.md) to keep field references type-safe. The compiler will catch misspelled or removed field names at build time.

## Field options[​](#field-options "Direct link to Field options")

The `AppField.options` object controls rendering, validation, and behavior. There are 50+ available options. The table below lists the most commonly used ones.

### Form controls and rendering[​](#form-controls-and-rendering "Direct link to Form controls and rendering")

| Option                 | Type    | Purpose                                                                                                |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------ |
| `custom_form_control`  | string  | Override the default form widget: `'search-box'`, `'drop-down-simple'`, `'color'`, `'link-list'`, etc. |
| `gridview_renderer`    | string  | Custom list/grid cell renderer: `'circle_percent'`, `'indicator'`, `'rich_text_line'`, etc.            |
| `plain_renderer`       | string  | Custom plain-view renderer: `'colorful-lookup'`, `'avatar-image'`, `'work-progress-bar'`, etc.         |
| `code_editor_enabled`  | boolean | Show a code editor instead of a text input                                                             |
| `code_editor_language` | string  | Language for syntax highlighting: `'javascript'`, `'json'`, `'html'`, etc.                             |

### Validation and input[​](#validation-and-input "Direct link to Validation and input")

| Option                                  | Type          | Purpose                                                                       |
| --------------------------------------- | ------------- | ----------------------------------------------------------------------------- |
| `restrict_input`                        | string        | Input validation pattern: `'email'`, `'percent'`, `'url'`, `'phone'`, `'int'` |
| `input_mask`                            | string/object | Input mask (e.g. phone format)                                                |
| `max_length`                            | number        | Maximum character count                                                       |
| `decimal_places`                        | number        | Decimal precision for number fields                                           |
| `number_min_value` / `number_max_value` | number        | Numeric range validation                                                      |

### Defaults and help text[​](#defaults-and-help-text "Direct link to Defaults and help text")

| Option                     | Type               | Purpose                              |
| -------------------------- | ------------------ | ------------------------------------ |
| `default_value_expression` | string/bool/number | Default value applied to new records |
| `help_text`                | LanguageTextObject | Tooltip/help text shown on the field |
| `placeholder_text`         | LanguageTextObject | Placeholder text in the input        |

### Lookup display[​](#lookup-display "Direct link to Lookup display")

| Option                        | Type   | Purpose                                         |
| ----------------------------- | ------ | ----------------------------------------------- |
| `lookup_entries_formatting`   | object | Per-lookup-entry colors, icons, and text colors |
| `lookup_entries_localization` | object | Per-lookup-entry translations                   |

### Access and lifecycle[​](#access-and-lifecycle "Direct link to Access and lifecycle")

| Option                   | Type    | Purpose                                                               |
| ------------------------ | ------- | --------------------------------------------------------------------- |
| `access`                 | string  | Field access level: `'workspaceAdmin'`, `'workspaceTeam'`, `'groups'` |
| `changeset_hide`         | boolean | Hide field changes from the change history                            |
| `clear_on_transition`    | boolean | Clear the field value when an action executes                         |
| `conditional_formatting` | string  | Dynamic formatting function name                                      |

Options are additive. A field with no options uses the engine's default widget and validation for its data type. Add options only when you need to override that default.

### Display formatting[​](#display-formatting "Direct link to Display formatting")

| Option                   | Type               | Purpose                                                                         |
| ------------------------ | ------------------ | ------------------------------------------------------------------------------- |
| `formatting_pre`         | LanguageTextObject | Prefix displayed before the value (e.g., `"$"`)                                 |
| `formatting_post`        | LanguageTextObject | Suffix displayed after the value (e.g., `"h"`, `"kg"`)                          |
| `special_decimal_format` | string             | Special numeric formatting: `'HH:MM'` renders decimals as hours<!-- -->:minutes |

### Schema type markers[​](#schema-type-markers "Direct link to Schema type markers")

When the API returns a schema (via `/api/schema/{WS}!{APP}`), each field includes an `ed_custom_field_type` property that identifies how the field behaves in the system:

| Schema type             | Meaning                         | Example fields                       |
| ----------------------- | ------------------------------- | ------------------------------------ |
| `authorinfo`            | Person field (stores user GUID) | `keeper_id`, `created_by_account_id` |
| `lookup_custom`         | Lookup with custom values       | `state`, `priority`                  |
| `lookup_link_to_entity` | Link to another record          | `parent_id`, `c_related_task`        |
| `linklist`              | Multi-link field                | `record_links`                       |
| `peoplelist`            | Multi-person field              | `assignees_list`                     |
| `file` / `filelist`     | File attachment field           | `attachments`                        |
| `richtext`              | Rich text (Lexical editor)      | `description`                        |

These markers determine how the API resolves values during read and write operations. For example, `authorinfo` fields accept both user GUIDs and full names - the API resolves names to GUIDs automatically.

## Multi-language support[​](#multi-language-support "Direct link to Multi-language support")

Field captions and several text options support multiple languages through the `LanguageTextObject` type. Supported language codes are defined by `CaptionLanguage`:

```
type CaptionLanguage = 'en' | 'uk' | 'ru' | 'zh' | 'de' | 'fr' | 'es';
```

Use a language map anywhere the engine expects translatable text:

```
caption: { en: 'Priority', uk: 'Пріоритет' }
```

The following field properties accept `LanguageTextObject` values: `caption`, `help_text`, `placeholder_text`, `formatting_pre`, `formatting_post`, and default value expressions.

## Calculated fields[​](#calculated-fields "Direct link to Calculated fields")

Calculated fields derive their values from other fields or from related records. They use one of the `CalcType` values instead of a `DataType`.

| Calc type        | Behavior                                          | Execution                |
| ---------------- | ------------------------------------------------- | ------------------------ |
| `calcfield`      | Simple formula over the current record's fields   | Synchronous              |
| `rollup`         | Aggregate value from child records                | Asynchronous (Processor) |
| `datarollup`     | Data-level rollup                                 | Asynchronous (Processor) |
| `treerollup`     | Aggregate across a tree hierarchy                 | Asynchronous (Processor) |
| `shadow`         | Denormalized copy of a field from a linked record | Asynchronous (Processor) |
| `tablecalcfield` | Editable grid calculation                         | Asynchronous (Processor) |

Simple `calcfield` formulas execute synchronously when the record loads. All other calc types are asynchronous - the background Processor evaluates them after the triggering change is saved.

Calc field definitions live in `fields/calc-fields/index.ts`. The build system bundles this directory separately so the formulas can run in the browser without pulling in server-only code. See [Package structure](/developer-guide/app-architecture/package-structure.md) for where this fits in the directory layout.

## Field naming conventions[​](#field-naming-conventions "Direct link to Field naming conventions")

Custom fields use the `c_` prefix - for example `c_priority`, `c_due_date`, `c_total_cost`. This prefix distinguishes app-specific fields from system fields.

System fields are provided by `@comind/base` and have no prefix: `title`, `description`, `state`, `creation_date`, `update_date`, `keeper_id`, and so on. Every app inherits these automatically.

When referencing fields in [actions](/developer-guide/building-blocks/actions.md), [view logic](/developer-guide/building-blocks/view-logic.md), or [form layouts](/developer-guide/building-blocks/form-layouts.md), always use the db name (`c_priority`, not the caption). The TypeScript type system will enforce correct names at compile time.

Tutorials

For step-by-step walkthroughs of adding fields to an app, see:

* [Create new field](/developer-guide/tutorials/tutorial-customize-app/create-new-field.md) - add a boolean field and place it on the form layout
* [Create new calculated field](/developer-guide/tutorials/tutorial-customize-app/create-new-calculated-field.md) - add a formula-based field that computes values from other fields
