User Defined Fields (UDF)
You can create your own fields under the Clients, Users, Project, and Suppliers modules. In the Projects module, you can find the extra fields in the Overview tab, beneath the map.

User defined fields (UDF) can be only created in the API Admin. Normally, your Kompass Champion should have access on the API Admin.
To create your fields, you will initially have to create a Project UDF schema. Head to "Client/ User/ Project/ Supplier UDF Schema" (1) and click "Add UDF schema" (2).

Add a name and then you'll have to set the schema.

Please note that once you have create your UDF schema, you will have to allocate it to your org. Head to your org page and select the schema at the relevant module.
Understanding the Schema Definition
You can see the basic structure of a UDF schema below:
{
"type": "object",
"properties": {
"field_name": {
"type": "string",
"label": "Field Label",
"default": null,
"x-order": 1
}
},
"required": [
"field_name"
]
}
Field Properties
As seen above, you can use certain properties under the field_name.
| Property | Description | Example |
|---|---|---|
type |
Field data type (see Field Types) | "string" , ["string", "null"] |
label |
Display label shown in the UI | "Company Name" |
default |
Default value when field is empty | null , "" , 0 , false |
enum |
List of allowed values (creates dropdown) | ["Active", "Inactive", "Pending"] |
There are additional custom extensions available from your fields (x- prefixed)
| Property | Description | Applies To | Example |
|---|---|---|---|
x-order |
Display order (lowest first) | All fields | 1 , 2 , 3 |
x-widget |
Override default widget (see Widgets) | Entity reference fields | "date" , "client" |
x-depends-on |
Parent field (clears when parent changes) | Required: contact , quote_item , task |
"client_id" , "project_id" |
x-module |
Module context for tags | Required: tags widget |
"clients" , "projects" |
x-multi-line |
Enable textarea mode | String fields (required if x-rows is set) |
true , false |
x-rows |
Number of textarea rows | String fields (requires x-multi-line: true ) |
3 , 5 , 10 |
Field Types
1. Text Field
This is a standard string field used for capturing text, such as notes or simple descriptions. You can allow it to be left empty by setting the type to ["string", "null"] .
- Example Use: A "Plot" description.
Code Definition:
JSON
"plot": {
"type": "string",
"label": "Plot",
"x-order": 1,
"default": null
}
Code Definition (with null allowed):
JSON
"plot": {
"type": [
"string",
"null"
],
"label": "Plot",
"x-order": 1,
"default": null
}
2. Checkbox (Yes/No)
This is a boolean field that appears as a simple checkbox. It's ideal for tracking true/false or yes/no information.
- Example Use: A "RAMS Sent" checkbox.
Code Definition:
JSON
"rams": {
"type": "boolean",
"label": "RAMS Sent",
"default": false
}
3. Dropdown List
This field allows users to select a single option from a predefined list. Use the enum property to list the available options. Including null in the enum list makes the field optional.
- Example Use: A "State Area" field.
Code Definition:
JSON
"section": {
"enum": [
"Central",
"East",
"North",
"South",
"West",
null
],
"type": [
"string",
"null"
],
"label": "State Area",
"x-order": 2,
"default": null
}
4. Date Field
This field provides a calendar picker. By setting the format to date , you ensure the input is correctly handled as a date.
- Example Use: An "Archive Date".
Code Definition:
JSON
"archive_date": {
"type": [
"string",
"null"
],
"format": "date",
"label": "Archive Date",
"x-order": 3,
"x-widget": "date",
"default": null
}
5. Number Field
This field is used for entering numerical data only. You can set a default value, such as 0 .
- Example Use: An "Acres" field.
Code Definition:
JSON
"acres": {
"type": [
"number",
"null"
],
"label": "Acres",
"x-order": 4,
"default": 0
}
Making Fields Required/Optional
Required Fields
Fields are required by default. To make a field mandatory:
{
"type": "object",
"properties": {
"company_name": {
"type": "string",
"label": "Company Name"
}
},
"required": [
"company_name"
]
}
Optional Fields (Nullable)
To allow null values, use an array type with "null" :
{
"type": [
"string",
"null"
],
"label": "Optional Field",
"default": null
}
Examples:
// Optional string
{
"type": [
"string",
"null"
],
"label": "Middle Name",
"default": null
}
// Optional integer
{
"type": [
"integer",
"null"
],
"label": "Employee Number",
"default": null
}
// Optional number
{
"type": [
"number",
"null"
],
"label": "Discount Rate",
"default": null
}
UI Behaviour:
- Fields with
"null"in type array will show a clear button (×) when in edit mode - Clearing the field sets the value to
null - Empty strings in nullable fields are automatically converted to
null
Widgets
Widgets determine how fields are rendered in the UI. Most widgets are automatically selected based on the field type. The x-widget property is only used to specify special selector widgets.
Automatic Widget Selection
The widget is automatically determined by the field type:
| Type | Condition | Rendered As | UI Component |
|---|---|---|---|
string |
Has enum |
Dropdown | KSelect |
string |
No enum |
Text field | KTextField |
integer |
- | Number field | KTextField |
number |
- | Number field | KTextField |
boolean |
- | Checkbox | KCheckbox |
String Field Options:
x-multi-line: Enable textarea mode (true/false). Iftrueandx-rowsis not specified, defaults to 1 row.x-rows: Number of rows for textarea (integer, requiresx-multi-line: true)
Examples:
// Simple text field
{
"type": "string",
"label": "Name"
}
// Textarea field
{
"type": "string",
"label": "Description",
"x-multi-line": true,
"x-rows": 5
}
// Dropdown (enum)
{
"type": "string",
"label": "Status",
"enum": [
"Active",
"Inactive"
]
}
// Number field
{
"type": "integer",
"label": "Count"
}
// Checkbox
{
"type": "boolean",
"label": "Enabled"
}
Special Selector Widgets (via x-widget)
Use x-widget to specify special selector components for entity references. These must be explicitly set and require integer or array types.
Date Widget
{
"type": [
"string",
"null"
],
"label": "Due Date",
"x-widget": "date",
"default": null
}
Divider Widget
Renders a horizontal divider line that spans the full width. Useful for visually grouping fields.
{
"type": "null",
"x-widget": "divider",
"default": null
}
With text label:
{
"type": "null",
"x-widget": "divider",
"label": "Personal Information",
"default": null
}
Note: Divider widgets don't store data. Use the label property to display text in the middle of the divider line.
Client Widget
{
"type": [
"integer",
"null"
],
"label": "Client",
"x-widget": "client",
"default": null
}
Contact Widget
Requires: x-depends-on (field containing client ID)
{
"type": [
"integer",
"null"
],
"label": "Contact",
"x-widget": "contact",
"x-depends-on": "client_id",
"default": null
}
Filters contacts by the selected client.
Project Widget
{
"type": [
"integer",
"null"
],
"label": "Project",
"x-widget": "project",
"default": null
}
Quote Item Widget
Requires: x-depends-on (field containing project ID)
{
"type": [
"integer",
"null"
],
"label": "Quote Item",
"x-widget": "quote_item",
"x-depends-on": "project_id",
"default": null
}
Filters quote items by the selected project.
Task Widget
Requires: x-depends-on (field containing project ID or quote item ID)
{
"type": [
"integer",
"null"
],
"label": "Task",
"x-widget": "task",
"x-depends-on": "project_id",
"default": null
}
Filters tasks by the selected project or quote item. The x-depends-on value can be either "project_id" or "quote_item_id" .
Supplier Widget
{
"type": [
"integer",
"null"
],
"label": "Supplier",
"x-widget": "supplier",
"default": null
}
User Widget
{
"type": [
"integer",
"null"
],
"label": "Assigned To",
"x-widget": "user",
"default": null
}
Tags Widget
{
"type": [
"array",
"null"
],
"label": "Tags",
"x-widget": "tags",
"x-module": "clients",
"default": null
}
Options:
x-module: Module context for tags (e.g.,"clients","projects","tasks")
Field Dependencies
Fields can depend on other fields using x-depends-on . When the parent field changes, dependent fields are automatically cleared.
Example: Client → Contact
{
"type": "object",
"properties": {
"client_id": {
"type": [
"integer",
"null"
],
"label": "Client",
"x-widget": "client",
"x-order": 1,
"default": null
},
"contact_id": {
"type": [
"integer",
"null"
],
"label": "Contact",
"x-widget": "contact",
"x-depends-on": "client_id",
"x-order": 2,
"default": null
}
}
}
Behaviour:
- Contact selector is filtered by selected client
- When client changes, contact field is cleared to
null - Dependency chains are supported (A → B → C)
Example: Project → Quote Item → Task
{
"type": "object",
"properties": {
"project_id": {
"type": [
"integer",
"null"
],
"label": "Project",
"x-widget": "project",
"x-order": 1,
"default": null
},
"quote_item_id": {
"type": [
"integer",
"null"
],
"label": "Quote Item",
"x-widget": "quote_item",
"x-depends-on": "project_id",
"x-order": 2,
"default": null
},
"task_id": {
"type": [
"integer",
"null"
],
"label": "Task",
"x-widget": "task",
"x-depends-on": "quote_item_id",
"x-order": 3,
"default": null
}
}
}
Complete Example
{
"type": "object",
"properties": {
"status": {
"type": "string",
"label": "Status",
"enum": [
"New",
"In Progress",
"Completed",
"On Hold"
],
"default": "New",
"x-order": 1
},
"client_id": {
"type": [
"integer",
"null"
],
"label": "Related Client",
"x-widget": "client",
"x-order": 2,
"default": null
},
"contact_id": {
"type": [
"integer",
"null"
],
"label": "Primary Contact",
"x-widget": "contact",
"x-depends-on": "client_id",
"x-order": 3,
"default": null
},
"priority": {
"type": "integer",
"label": "Priority Level",
"default": 3,
"x-order": 4
},
"budget": {
"type": [
"number",
"null"
],
"label": "Budget",
"default": null,
"x-order": 5
},
"due_date": {
"type": [
"string",
"null"
],
"label": "Due Date",
"x-widget": "date",
"x-order": 6,
"default": null
},
"is_billable": {
"type": "boolean",
"label": "Billable",
"default": true,
"x-order": 7
},
"notes": {
"type": [
"string",
"null"
],
"label": "Notes",
"x-multi-line": true,
"x-rows": 5,
"x-order": 8,
"default": null
},
"assigned_to": {
"type": [
"integer",
"null"
],
"label": "Assigned To",
"x-widget": "user",
"x-order": 9,
"default": null
},
"tags": {
"type": [
"array",
"null"
],
"label": "Tags",
"x-widget": "tags",
"x-module": "projects",
"x-order": 10,
"default": null
}
},
"required": [
"status",
"priority",
"is_billable"
]
}
Validation
Backend Validation
All UDF data is validated against the schema on save:
- Type checking (string, integer, number, boolean)
- Required field validation
- Enum value validation
- Field dependencies are checked
Frontend Validation
The UI provides real-time validation:
- Required fields show error if empty
- Number fields validate numeric input
- Integer fields validate integer input
- Nullable fields can be cleared
Validation Errors
Validation errors are returned in the format:
{
"udf": {
"field_name": "Error message"
}
}
Best Practices
- Always specify x-order: Ensures consistent field ordering
- Use null for optional fields: Include
"null"in type array - Set sensible defaults: Provide default values for all fields
- Use dependencies wisely: Create logical field relationships
- Keep labels concise: Use clear, short labels (2-4 words)
- Document custom widgets: Use comments to explain complex schemas
- Test validation: Verify required/optional field behaviour
- Consider field width: Fields are displayed in 3-column layout
Common Patterns
Optional Reference Field
{
"type": [
"integer",
"null"
],
"label": "Related Entity",
"x-widget": "client",
"default": null
}
Required Dropdown
{
"type": "string",
"label": "Category",
"enum": [
"A",
"B",
"C"
],
"default": "A"
}
Dependent Selectors
{
"parent_id": {
"type": [
"integer",
"null"
],
"x-widget": "client",
"x-order": 1
},
"child_id": {
"type": [
"integer",
"null"
],
"x-widget": "contact",
"x-depends-on": "parent_id",
"x-order": 2
}
}
Large Text Field
{
"type": [
"string",
"null"
],
"label": "Description",
"x-multi-line": true,
"x-rows": 8,
"default": null
}