Bitbucket modules
Common modules
Compass modules
Confluence modules
Jira modules
Jira Service Management modules
Rovo modules (Preview)

Jira custom field type

The jira:customFieldType module lets you create a new custom field type in Jira, which lets Jira administrators create new custom fields based on that type.

Data types

Each field type has to be based on a predefined data type.

The data type controls what kind of values the REST API accepts and returns for the field, the field's behavior in JQL, and the default rendering behavior.

The available data types are:

  • string - values represent plain strings. JQL offers autocomplete and exact comparison.
  • number - values represent numbers (double-precision 64-bit IEEE 754 floating points).
  • user - values represent users identified by Atlassian account IDs. The field behaves like any other user field in Jira when you interact with it in the UI or the REST API.
  • group - values represent groups identified by names. The field behaves like any other group field in Jira when you interact with it in the UI or the REST API.
  • object - values are arbitrary JSON objects. See below for more details.
  • datetime - values are strings that represent dates with time and timezone. The field behaves like any other datetime field in Jira when you interact with it in the UI or the REST API. However, if milliseconds are provided, they are ignored.
  • date - values are strings that represent dates. The field behaves like any other date field in Jira when you interact with it in the UI or the REST API.

Object type

The object type makes use of additional properties compared to other types.

The required formatter property contains a Jira expression that returns a string. This string is used to represent the value if the rendering function is not provided, or where the rendering function is not supported. For example, the column view in the Global Issue Navigator.

The optional schema property contains the JSON schema that is used to validate values stored in the field.

By default, you can search for a text string anywhere in the content of an object-type field. To enable more fine-grained searching, create Field properties with the searchAlias schema property .

This means that, for a field named X:

  • using the default behavior you can search the entire value stored in this field using X ~ "text to search for"
  • by defining a field property, such as Y, in the schema with searchAlias, you can search that field property using X.Y = value.

The JQL type of each property created with searchAlias is derived from the schema type, using these rules:

  • string schema type becomes a string in JQL.
  • number schema type becomes a number in JQL.
  • integer schema type becomes a number in JQL.
  • boolean schema type becomes a string in JQL.
  • array schema type becomes an array of items of a type following these rules. For example, an array containing items with the schema type integer becomes an array of items with the type number in JQL.
  • search aliases for any other schema type are ignored.

It's possible to override the schema type with searchType. This enables you to use the complex types supported in JQL but not available in the JSON schema. The following search types are available:

Pairs of conflicting field properties, those with the same name and path but different types, are ignored.

Object type JQL search example

This is an example of a field that stores money. It showcases the use of:

  • the formatter and schema properties.
  • JQL search aliases.
1
2
  jira:customField:
    - key: cf-type-money
      name: Development cost
      description: Tracks the development cost of features, in different currencies
      type: object
      formatter: 
        expression: "`${value.amount} ${value.currency}`"
      schema:
        properties:
          amount:
            type: number
            searchAlias: Amount
          currency:
            type: string
            enum: [ "USD", "EURO", "AUD" ]
            searchAlias: Currency
          spender:
            type: string
            searchType: user
            searchAlias: Spender
        required: [ "amount", "currency" ]

The schema ensures that values of this field look like this:

1
2
{
  "amount": 100,
  "currency": "USD",
  "spender": "<account-id>"
}

With the formatter in place, displayed on the issue search, the value will be a string 100 USD.

In addition to the default text search of the entire field value, more fine-grained search using these field properties is available:

  • Amount (JQL type: number),
  • Currency (JQL type: string),
  • Spender (JQL type: user).

Collection types

A Forge custom field can store a collection of up to 100 values. This is done by declaring the collection property, which specifies the collection type. For example, to create a field that stores a list of strings, declare it as:

1
2
type: string
collection: list

These data types can be part of a collection:

  • string
  • group
  • user

Using any other data type in combination with collection:list prevents the field from appearing in Jira.

Field lifecycle

This module makes a new custom field type available in Jira. Custom fields of that type can now be created by Jira admins via:

Jira admins can manage fields created this way, just like all other manually created custom fields. The following operations are available:

When the app is uninstalled or if the field type is removed from the manifest, all fields of that type disappear. If the app is reinstalled within 30 days, or the field type is restored, the fields will reappear with the previous data intact. All changes made to the field type in the manifest (e.g. changing the name) are reflected in Jira after the app is deployed. (Warning: changing the data type after the field has been used with the old type is not supported, and will result in undefined behavior, potentially making the field unusable.)

The ID of the custom field type has format ari:cloud:ecosystem::extension/{app-id}/{environment-id}/static/{module-key}, where:

  • {app-id} is your app ID defined in the manifest.
  • {environment-id} is the ID associated with the installation environment.
  • {module-key} is the key of the custom field type module defined in the manifest.

If you need to fetch this ID in your app (for example, to create an instance of your type with the REST API), use the localId property from the product context. It has the following format:

1
2
ari:cloud:ecosystem::extension/<app-id>/<environment-id>/static/<invoked-module-key>

You can use it to create the ID of your custom field type. There are two ways to get the product context, depending on your app's rendering method:

Read-only fields

Read-only fields are those that have readOnly set to true in their definition in the manifest. They aren't editable by users, neither through the UI nor the Edit issue REST API.

They are great for showing values derived from the issue state. While you can show anything using issue panels, issue glances or issue context panels, custom fields may be a better choice if you need all their benefits, such as JQL search, configuration on screens, or being part of the issue import and export.

The value of such fields has to be calculated beforehand and set with the dedicated REST API. One pattern to achieve this is to listen to product triggers for events that may affect the values and update the values as necessary.

Additionally, updating the value on every issue view can be achieved with the value function.

Note that read-only fields won't be rendered on issue create or transition screens.

Configuration

Apps can store configuration information against custom field contexts. This is achieved by plugging into the custom field context configuration interface with the contextConfig property in the manifest.

You can provide the configuration interface with UI Kit or Custom UI, by declaring either a function or a resource in the manifest:

1
2
modules:
  jira:customField:
    contextConfig:
      resource: custom-ui-resource

In UI Kit 1, the function must return a CustomFieldContextConfig component with the onSubmit handler, and the UI Kit and Custom UI resource uses the submit API to submit the configuration value.

In the context configuration, apps can store value schemas for object type fields. This is done by providing the schema property in addition to the configuration property.

Ultimately, the shape of the value that the app submits looks like this:

1
2
{
  "configuration": "<configuration data>",
  "schema": "<field value schema>"
}

Where configuration is the configuration data, and the optional property schema is the value schema.

It's also possible to manage configurations manually with the Issue custom field configuration (apps) resource.

The app can access configuration values in expressions that can be provided in different places in the custom field type definition in the manifest, or directly with the Get custom field configurations REST API.

Configuration example

For example, you can use configuration details in conjunction with a validation expression to configure maximum and minimum values for a custom number field. To do this, save a configuration with this shape:

1
2
{
    "minValue": 0,
    "maxValue": 100    
}

In Custom UI, this would be done with the following line:

1
2
await view.submit({ configuration: { minValue: 0, maxValue: 100 } });

This configuration is available in validation.expression in the manifest definition of the custom field type, and you can use it to validate the field value against the configured bounds:

1
2
jira:customFieldType:
  - key: cf-type-min-max
    name: Min-max custom field
    description: A field with configurable min/max values
    type: number
    validation:
      expression: "value <= configuration.maxValue && value >= configuration.minValue"
      message: The value is not within the configured bounds

Validation

A field value can be validated with Jira expressions.

Validation takes place whenever an issue is edited or created, but not when the app updates the value directly with the private field update REST API.

The following context variables are available in the validation expression:

  • user (User): The user that wants to modify the field value.

  • issue (Issue): The edited issue.

  • project (Project): The project the issue belongs to.

  • fieldId (String): The ID of the field. For example, customfield_10020.

  • configuration: The configuration stored against the custom field context. Typically a map. Depending on the value of the configuration data, this may also be any primitive (number, string, boolean) or a list.

  • value: The value that's being set on the field. The type of this variable depends on the data type of the field and can be one of the following:

    • String, if the data type is string or group.
    • Number, if the data type is number.
    • User, if the data type is user.
    • Map, if the data type is object.
    • Date, if the data type is datetime.
    • CalendarDate, if the data type is date.

    If the field stores a collection, the value type will be a List with items of one of the types specified above.

The expression can return three types of values:

  • true means that the validation was successful, and the operation is allowed.
  • false means that the value is invalid. The error message defined in the manifest's validation.errorMessage property will be shown to the user.
  • String means that the value is invalid. The returned string will be shown as the error message to the user.

Validation example 1

Allow only numbers between 0 and 100, plus empty (null) values:

1
2
validation:
  expression: value == null || value >= 0 && value <= 100
  errorMessage: Only values between 0 and 100 are allowed.

Validation example 2

Allow only users from group field-editors to edit the value of the field, unless it's a new issue being created, and the field value is empty.

1
2
validation:
  expression: |-
    let isIssueCreate = issue == null || issue.id == null;
    let isEmpty = value == null; 
    let hasPermission = user.groups().includes('field-editors');
    isIssueCreate && isEmpty || hasPermission
  errorMessage: You don't have permission to edit this field. 

See the documentation for Jira expressions to find out what else is possible.

Rendering

Forge apps can provide rendering of the field with UI Kit.

Custom rendering can't be implemented using Custom UI.

UI Kit
1
2
modules:
    jira:customField:
      resource: key
      render: native

You can obtain the current value of the field from the useProductContext hook, like this:

1
2
const context = useProductContext();
const fieldValue = context?.extension.fieldValue;
UI Kit 1
1
2
modules:
  jira:customField:
    function: key

In UI Kit 1, the rendering function must return a CustomField component. Inside the function, you can obtain the value, ID, and type of the field from the useProductContext hook, like this:

1
2
const { extensionContext: { fieldValue, fieldId, fieldType } } = useProductContext();

Editing

Forge apps can optionally provide their own editing experience of the field with UI Kit or Custom UI by specifying the edit property.

UI Kit

With UI Kit, use the CustomFieldEdit component to render the edit view.

1
2
modules:
    jira:customField:
      edit:
        resource: key
        render: native

You can obtain the current value of the field from the getContext API, like this:

1
2
const { fieldValue } = await view.getContext();

To update the field value, use the submit API, like this:

1
2
await view.submit(fieldValue);

Default editing, appropriate to the field's data type, is used if the edit resource is not provided.

Custom UI
1
2
modules:
    jira:customField:
      edit:
        resource: key

You can obtain the current value of the field from the getContext API, like this:

1
2
const { fieldValue } = await view.getContext();

To update the field value, use the submit API, like this:

1
2
await view.submit(fieldValue);

Default editing, appropriate to the field's data type, is used if the edit resource is not provided.

UI Kit 1
1
2
modules:
  jira:customField:
    edit:
      function: key

In UI Kit 1, the edit function must return a CustomFieldEdit component. Inside the function, you can obtain the current value, id, and full type of the field from the useProductContext hook, like this:

1
2
const { extensionContext: { fieldValue, fieldId, fieldType } }  = useProductContext();

Default editing, appropriate to the field's data type, is used if the edit function is not provided.

Issue view

By default, when you define an editing function for a Jira custom field created by a Forge app, switching to the field’s edit mode opens a modal. However, when using UI Kit or Custom UI, you can enable inline editing by including the isInline property in the app’s manifest.

1
2
modules:
    jira:customField:
      edit:
        resource: key
        render: native
        isInline: true

The isInline property is added temporarily for a deprecation period of modal experience and will be removed on April 1st, 2025. After this date all fields on issue view will be rendered inline by default. If you still want to use modal experience in your fields, use the Modal component for UI Kit fields and the Modal bridge API for Custom UI fields.

For UI Kit, use the CustomFieldEdit component to render the edit view. In issue view, the onSubmit function in the CustomFieldEdit component will be called on blur events, "Enter" key press, or on clicking confirmation action button, so you can place the submit logic there. Otherwise, you can create your own logic to use the submit API outside the onSubmit function.

Issue creation and issue transition dialog

Jira custom fields created by Forge apps that have editing functions defined can be added to the new Create issue dialog and Issue transition dialog by users with the appropriate permission. Validation of these fields is performed when the Create issue form is submitted.

In the Create issue dialog and Issue transition dialog, users can update field values inline. This means that the edit entry point is rendered directly in the dialog. Default edit rendering is used unless you specify otherwise. In apps using UI Kit, the entered value is submitted when the user clicks outside the field or elsewhere on the dialog. An issue is created only after the value has been submitted.

Your app can find out which view a field is rendered on using the renderContext property from the product context:

1
2
const { extensionContext: { renderContext } } = useProductContext();

To update a field's value before issue creation in apps using Custom UI or UI Kit, use the submit API:

1
2
await view.submit(fieldValue);

For UI Kit, use the CustomFieldEdit component to render the edit view. In the create issue dialog, the onSubmit function in the CustomFieldEdit component will be called on blur events, so you can place the submit logic there. Otherwise, you can create your own logic to use the submit API outside the onSubmit function.

After issue creation is confirmed, non-required custom fields need to resolve a promise to update their value within 10 seconds. If they don't, the issue will be created with the default values.

For the Issue transition dialog we currently only support fields with type object, string, and number.

Formatter

The formatter is used to render the field on views where rendering with functions is not supported, for example in email notifications or on the global issue navigator page.

Formatters are declared with Jira expressions, making them fast enough to be invoked synchronously whenever a rendered human-readable field value is required.

If a formatter expression is applied to a set of issues, the number of expensive operations executed by it must be constant. In other words, the expression must not contain any operations labeled with N.

The following context variables are available in the formatter expression:

  • user (User): The current user.

  • issue (Issue): The rendered issue.

  • project (Project): The project to which the issue belongs.

  • fieldId (String): The ID of the field. For example, customfield_10020.

  • configuration: The configuration stored against the custom field context. Typically a map. Depending on the value of the configuration data, this may also be any primitive (number, string, boolean) or a list.

  • value: The field's value. The type of this variable depends on the data type of the field and can be one of the following:

    • String, if the data type is string or group.
    • Number, if the data type is number.
    • User, if the data type is user.
    • Map, if the data type is object.
    • Date, if the data type is datetime.
    • CalendarDate, if the data type is date.

    If the field stores a collection, the value type will be a List with items of one of the types specified above.

Using formatters in CSV export

By default, formatters aren't used for issue export to CSV. Thanks to this, exported values can be seamlessly imported back to Jira.

To change that behavior, set the export property to true:

1
2
formatter:
  expression: "formatter expression"
  export: true

We recommend using this option in combination with specifying a parser, to make importing such an export possible.

Formatter example 1

In the simplest possible case, your formatter will just transform the current value without requiring any additional information. For example, you can render a text-based progress bar for a field that stores progress as a number between 0 and 100:

1
2
formatter:
  expression: "`${'▰'.repeat(value / 10).padEnd(10, '▱')} (${value}%)`"

Formatter example 2

Imagine you have a string field whose values are IDs of some external components. A Forge function that renders this field makes a call to your service to resolve those IDs into human-readable names. While such external calls are not possible in Jira expressions, you can store the mapping between IDs and names in an entity property, and read it in the formatter:

1
2
formatter:
  expression: |-
    let mapping = project.properties.get('idToNameMapping');
    mapping.get(value)

Since your app stores the data required to format the field on the Jira side, the user experience remains fast and reliable.

See the documentation for Jira expressions to find out what else is possible.

Value Function

Forge apps can provide a value function that computes the value of the field.

This function is invoked on every issue view, so that the freshly computed value is shown to the user whenever they open the issue page. Jira also saves this value into the database against the issue. Thanks to this, the value is not only available for that one particular user interaction, but also becomes immediately refreshed for the REST API, all other views, JQL search, etc.

This is useful mostly for read-only fields that show some derived data. Because the value function is invoked only on the issue view, you will most likely still need to listen to events and update values asynchronously. However, you can at least guarantee that users will always see a fresh value on the issue view.

Manifest example:

1
2
  jira:customField:
    - key: field-key
      name: Name
      type: string
      value:
        function: computeValue

The function receives a list of issue IDs and returns a list of values for those issues. Context configuration is provided for the issues, so the app does not have to load context configuration in the function.

Here is a payload example:

1
2
{
  "field": {
    "id": "customfield_10000",
    "key": "4886f49a-482d-41ba-bd73-6aeb5ee40e0f__DEVELOPMENT__my-custom-field-key",
    "type": "ari:cloud:ecosystem::extension/4886f49a-482d-41ba-bd73-6aec5ee40e0f/4e9fe62d-2575-4b2d-b0d7-5a37f43a80a9/static/my-custom-field-key",
    "name": "My custom field"
  },
  "issues":[
    {
      "id":10001,
      "context":10136,
      "value": "value1"
    },
    {
      "id":10002,
      "context":10136,
      "value": "value2"
    }
  ],
  "contexts": [
    {
      "id": "10136",
      "configuration": "custom data"
    }
  ]
}

Here is an example of how to define the value function:

1
2
    function valueFunctionName(arg) {
        return arg.issues.map(issue => computeCurrentValue(arg.field, issue.id));
    }

    function computeCurrentValue(field, issueId) {
       // return the value of the field for the given issue ID
    }

The values returned must be compatible with the format expected by the Edit Issue REST API operation.

In the value function, make all calls to an Atlassian API as the app developer by using the api.asApp() method. asUser isn't supported. Remember that the newly computed value will be visible to all users, not only the user who triggered the update, so you shouldn't ever need to rely on user-specific behavior anyway.

For example, for the user type field the value must be an object that contains accountId. So the function would have to return a list of values like this:

1
2
[{
  "accountId": "<user-1>"
}, {
  "accountId": "<user-2>"
}, {
  "accountId": "<user-1>"
}]

The order of values returned must be the same as the order of issues received in the argument.

Note that the issue view is the only view where the value function is invoked. However, the function is still expected to work with multiple issues at once (accepting and returning lists). Other views may become supported, including ones that display more than one issue at a time. Therefore, make sure your function has constant performance regardless of the number of issues in the argument.

Rendering hierarchy

The rendering hierarchy goes from functions (highest priority), to formatter expressions, to default rendering (lowest priority).

On views that support rendering with functions, the function is used if defined. Otherwise, the formatter expression is used. If neither is defined, the default rendering for the field's data type is used.

On the issue view, if the value function is defined, it is invoked first, then its result is passed on to the rendering function, formatter expression, or the default rendering component.

On views that don't support rendering with functions, the formatter expression is used if defined in the manifest and supported on the view, otherwise the raw field value is shown.

Some views don’t support custom edit rendering, including: boards, issue navigator, bulk edit view, transition screen, and more. In these cases the default editing experience appropriate for the field’s data type is used.

Parser

The parser takes a string produced by the formatter and converts it into the shape expected by the field.

Use it when, on editing an issue, the user may provide a value that doesn’t conform to the underlying data type implementation of a field. In such cases, the parser will convert the input into storable values.

Formatted string values may appear when:

  • importing issues from CSV, especially when the formatter is used for export
  • interacting with Jira views that don’t support editing with Custom UI or UI Kit, such as bulk update
  • performing a JQL search
  • using the edit issue REST API

Example

As an example, let’s use an object type field that stores amounts of money in a given currency.

The actual values stored by the field would be JSON objects that look like this:

1
2
{
  "amount": 100,
  "currency": "USD"
}

To make the values human-readable, your app would declare a formatter that makes the values look like 100 USD.

Now, to make the field able to consume strings like 100 USD, the app should declare a parser that can take such a string and transform it into a JSON object:

1
2
parser:
  expression: |-
    let parts = value.split(' ');
    { 
      amount: Number(parts[0]), 
      currency: parts[1] 
    }

Specification

Parsers are declared with Jira expressions.

Parser input

The following context variables are available in the parser expression:

  • user (User): The current user.
  • issue (Issue): The issue being edited.
  • project (Project): The project to which the issue belongs.
  • fieldId (String): The ID of the field. For example, customfield_10020.
  • configuration: The configuration stored against the custom field context. Typically a map. Depending on the value of the configuration data, this may also be any primitive (number, string, boolean) or a list.
  • value: A string provided by the user.
Output

The parser is expected to return a value compatible with the underlying data type of the field, as specified in the table below.

Data typeParser return typeDetails
stringString
groupStringGroup name
numberNumber
userUser
objectMap
dateCalendarDate
datetimeDate

If the field stores a collection, the returned value should be a List with items of one of the types specified above.

Search suggestions

When writing JQL queries in advanced search, users expect to receive automatic suggestions for valid values. By default, we try to provide these suggestions automatically for Forge custom fields, differently for each data type. For example, for fields of type user, we compile the list of suggestions from the pool of all Jira users.

Apps can override this default behavior and provide their own custom suggestions. This is achieved by adding the searchSuggestions section into the field definition in the manifest. The suggestion provider can be either a Jira expression, or a Forge function.

In the search suggestions function, calls to an Atlassian API must be done as the app developer by using api.asApp(). Making requests on behalf of a user with api.asUser() won’t work.

Input

The Jira expression has access to the following context variables:

  • fieldId (String): The ID of the field. For example, customfield_10020.
  • fieldType (String): The type of the field. For example, ari:cloud:ecosystem::extension/4211172c-5e6b-4170-9fce-f3314107517e/3b0cdefc-4f24-4696-a7dd-1092d95637f9/static/module-key.
  • fieldName (String): The name of the field. For example, Issue progress.
  • user (User): The user who is receiving the suggestions.
  • query (String): The string that the user already typed into the editor as the value of the field. Use it to narrow down the list of suggestions.

Similarly, the function receives an argument object with the same set of information:

1
2
{
  "fieldId": "<The ID of the field>",
  "fieldType": "<The type of the field>",
  "fieldName": "<The name of the field>",
  "query": "<the value entered by the user>",
  "user": {
    "accountId": "<the ID of the user that is requesting the suggestions>"
  },
  "context": {
    "cloudId": "<the ID of the instance the app is running on>"
  }
}

The following example shows a signature that can serve as a starting point for your function's implementation:

1
2
export function generateSearchSuggestions({ fieldId, fieldType, query, user: { accountId }, context: { cloudId }}) {
    // your implementation goes here
}

Output

The function or expression must return a list of suggestions. Each suggestion can be either a plain string, or an object that contains the value that’s used in JQL when the user selects the suggestion, and a label that the user sees on the list:

1
2
[
  {
    "value": "340f8126-50f7-4fe7-8765-1a151678b917",
    "label": "Value 1"
  },
  {
    "value": "771617fc-7417-4a4a-8b47-9230bbac47a0",
    "label": "Value2 2"
  }
]

If your values are already human-readable, you can just return plain strings:

1
2
["Value 1", "Value 2", "Value 3"]

Known limitations

While we're working hard to make Forge custom fields indistinguishable from regular custom fields, reaching full parity takes time. This section summarizes the features missing from Forge custom fields.

UI Kit and custom UI rendering

Rich rendering with UI Kit and custom UI is fully supported on the issue view and issue create screens. Other places use the formatter to display field values, and simple built-in components are offered for editing. For more details, see rendering hierarchy.

Eventually, we're planning to introduce fully custom rendering to as many places as possible.

Support in other products

Forge custom fields may not be fully supported in products other than Jira Cloud, such as Jira Mobile, Jira Service Management, or Confluence. Additionally, support in tools within Jira Cloud (for example, Jira automation) may be lacking.

We're constantly working on bringing the power of Forge fields to as many products and tools as we can.

We are waiting for your feedback

If there is an issue that you would particularly like to be solved, let us know by creating a ticket in the Forge Jira project.

Properties

PropertyTypeRequiredDescription
key

string

Yes A key for the module, which other modules can refer to. Must be unique within the manifest.

This key becomes a part of the key of each custom field of this type as described in the Custom field type lifecycle section.

Regex: ^[a-zA-Z0-9_-]+$

namestring or i18n objectYes

The name of the custom field type.

The i18n object allows for translation and is available to participants of the Internationalization for Forge EAP. See i18n object.

descriptionstring or i18n objectYes

The description of the custom field type.

The i18n object allows for translation and is available to participants of the Internationalization for Forge EAP. See i18n object.

iconstring

The icon displayed next to the type's name and description.


For custom UI and UI Kit apps, the icon property accepts a relative path from a declared resource. Alternatively, you can also use an absolute URL to a self-hosted icon. See Icons for more information.

If no icon is provided, or if there's an issue preventing the icon from loading, a generic app icon will be displayed.

typestringYesThe type of values stored by fields of this type. Available types are:
  • string
  • number
  • user
  • group
  • datetime
  • date
collectionnone|list (default: none) The kind of collection that the field values should be stored in. See collection types for more details.
validation.expressionstringA Jira expression that validates the field value. See validation for more details.
validation.errorMessagestring or i18n object

The error message to show when the validation expression returns false.

The i18n object allows for translation and is available to participants of the Internationalization for Forge EAP. See i18n object.

formatter.expressionstringRequired for the object type; otherwise, optionalA Jira expression that renders the value as a string. See formatter for more details.
formatter.exportbooleanWhether to use the formatter for values exported to CSV. See Using formatters in CSV export for more details.
parser.expressionstringA Jira expression that parses strings into valid values of this field. See parser for more details.
value.functionstring A function that computes the value of the field.

See value function for more details.

schemaobjectAllowed only for the object typeA JSON schema that describes values stored in the field.
searchSuggestions.expressionstringRequires either function or expression. Only one of the two properties must be present. A Jira expression that provides value suggestions in advanced search. See search suggestions for more details.
searchSuggestions.functionstringRequires either function or expression. Only one of the two properties must be present. A reference to the function module that provides value suggestions in advanced search. See search suggestions for more details.
readOnlybooleanWhether or not fields of this type are read-only. Read-only fields can't be edited by users. Defaults to false.
render'native'Yes for UI Kit.Indicates the module uses UI Kit.
functionstringRequired if using UI Kit 1 or triggers.A reference to the function module that defines the module.
resolver{ function: string } or
{ endpoint: string }
Yes

Set the function property if you are using a hosted function module for your resolver.

Set the endpoint property if you are using Forge remote to integrate with a remote back end.

edit.functionstringA reference to the function module that provides the editing experience for fields of this type.
edit.resourcestring A reference to the static resources entry that your edit entry point wants to display. See Resources for more details. To submit the view, use the submit API.
edit.render'native' Indicates if your edit entry point should display as UI Kit.
edit.isInlineboolean Indicates if your edit entry point should display inline on the issue view.
displayConditionsobjectThe object that defines whether or not the field is displayed on the issue view or global issue create (GIC) (other views or REST APIs are not affected). See display conditions.
contextConfig.functionstring A reference to the function module that provides the context configuration for fields of this type. The function must return the CustomFieldContextConfig component.
contextConfig.resourcestring A reference to the static resources entry that your configuration entry point wants to display. See Resources for more details. To submit the view, use the submit API.
contextConfig.render'native' Indicates if your configuration entry point should display as UI Kit.
contextConfig.layout UI Kit:
  • native
  • basic
Custom UI:
  • native
  • blank
  • basic (deprecated)
(default: native)
The layout of the page that defines whether a page is rendered with default controls (native), lays out the entire viewport with a margin on the left and breadcrumbs (basic for UI Kit), or is left blank allowing for full customization (blank for custom UI).

i18n object

Internationalization (i18n) for Forge apps is now available through Forge's Early Access Program (EAP). For details on how to sign up for the EAP, see the changelog announcement.

EAPs are offered to selected users for testing and feedback purposes. APIs and features under EAP are unsupported and subject to change without notice. APIs and features under EAP are not recommended for use in production environments.

For more details, see Forge EAP, Preview, and GA.

KeyTypeRequiredDescription
i18nstringYesA key referencing a translated string in the translation files. For more details, see Translations.

Extension data

UI Kit and Custom UI

Use the useProductContext hook to access the extension context in UI Kit or getContext bridge method in custom UI.

PropertyType/valueResourceDescription
type'jira:customFieldType'edit
contextConfig
The type of the module.
entryPoint'edit'
'contextConfig'
edit
contextConfig
The entry point of the module.
fieldIdstringedit
contextConfig
The ID of the field. For example, customfield_10020.
fieldTypestringedit
contextConfig
The type of the field. For example, ari:cloud:ecosystem::extension/4211172c-5e6b-4170-9fce-f3314107517e/3b0cdefc-4f24-4696-a7dd-1092d95637f9/static/module-key.
fieldValuestring
string[]
number
object
editThe value of the field. It has a type corresponding to the data type of the field.
issue.idstringeditThe ID of the issue on which the module is rendered.
issue.keystringeditThe key of the issue on which the module is rendered.
issue.typestringeditThe name of the type of the issue on which the module is rendered.
issue.typeIdstringeditThe ID of the type of the issue on which the module is rendered.
project.idstringeditThe ID of the project where the module is rendered.
project.keystringeditThe key of the project where the module is rendered.
project.type 'business'
'software'
'product_discovery'
'service_desk'
'ops'
editThe type of the project where the module is rendered.
renderContext'issue-view'
'issue-create'
'issue-transition'
editThe context in which the extension is rendered.
configurationIdnumbercontextConfigThe ID of the current configuration.
configurationanycontextConfigThe configuration stored for the custom field context.
fieldContextIdnumbercontextConfigReference to the field context ID the configuration is associated with.
issueTransition.idstringeditThe ID of the transition on which the module is rendered.
Only available for issue-transition render context.

UI Kit 1

Use the useProductContext hook to access the context in UI Kit 1.

Extension context

PropertyType/valueFunctionDescription
type'customFieldType'main
edit
contextConfig
The type of the module.
entryPoint'edit'
'contextConfig'
main
edit
contextConfig
The entry point of the module. Undefined for the main function.
fieldIdstringmain
edit
contextConfig
The ID of the field. For example, customfield_10020.
fieldTypestringmain
edit
contextConfig
The type of the field. For example, ari:cloud:ecosystem::extension/4211172c-5e6b-4170-9fce-f3314107517e/3b0cdefc-4f24-4696-a7dd-1092d95637f9/static/module-key.
fieldValuestring
string[]
number
object
main
edit
The value of the field. It has a type corresponding to the data type of the field.
renderContext'issue-view'
'issue-create'
'issue-transition'
main
edit
The context in which the extension is rendered.
configurationIdnumbercontextConfigThe ID of the current configuration.
configurationanycontextConfigThe configuration stored for the custom field context.
fieldContextIdnumbercontextConfigReference to the field context ID the configuration is associated with.

Platform context

PropertyType/valueFunctionDescription
issueIdstringmain
edit
The ID of the issue on which the module is rendered. Not available on issue create.
issueKeystringmain
edit
The key of the issue on which the module is rendered. Not available on issue create.
issueTypestringmain
edit
The name of the type of the issue on which the module is rendered.
issueTypeIdstringmain
edit
The ID of the type of the issue on which the module is rendered.
projectIdstringmain
edit
The ID of the project where the module is rendered.
projectKeystringmain
edit
The key of the project where the module is rendered.
issueTransition.idstringeditThe ID of the transition on which the module is rendered.
Only available for issue-transition render context.

Example

This example declares a progress bar custom field type that uses stored configuration details.

1
2
jira:customFieldType:
  - key: progress-bar-field-type
    name: Progress bar
    description: A custom field that shows a progress bar.
    icon: https://my-app.com/progress-bar-cf-type-icon
    type: number
    validation:
      expression: value == null || value >= (configuration?.minValue || 0) && value <= (configuration?.maxValue || 100)
      errorMessage: Only numbers between the maximum and minimum values are allowed.
    formatter:
      expression: |-
        let abs = x => x < 0 ? -x : x ;
        let round = x => Number((x+'').replace('\.\d+', '')) ;
        let MIN = configuration?.minValue || 0 ;
        let MAX = configuration?.maxValue || 100 ;
        let PERCENT = (value + abs(MIN)) / (abs(MAX) + abs(MIN)) * 100 ;
        `${'▰'.repeat(PERCENT / 10).padEnd(10, '▱')} (${round(PERCENT)}%)`
      export: true
    parser:
      expression: |-
        let MIN = configuration?.minValue || 0 ;
        let MAX = configuration?.maxValue || 100 ;
        let percent = Number(value.replace('[^\\d]', '')) ;
        MIN + ((MAX - MIN)*percent/100)
    searchSuggestions:
      expression: '["0", "25", "50", "75", 100"]'
    resource: displayProgressBar
    render: native
    edit:
      resource: editProgressBar
      render: native
    contextConfig:
      resource: configureProgressBar
      render: native
resources:
  - key: displayProgressBar
    path: src/frontend/index.jsx
  - key: editProgressBar
    path: src/frontend/editProgressBar.jsx
  - key: configureProgressBar
    path: src/frontend/configureProgressBar.jsx

Rate this page: