Last updated Oct 30, 2024

Custom UI

Custom UI provides a means of building the user interface of an app from scratch. The Custom UI runs within an iframe, providing an isolated environment for the app's interface to be displayed. Using custom UI, you can define your own user interface using static resources, such as HTML, CSS, JavaScript, and images. The Forge platform hosts your static resources, enabling your app to display custom UI on Atlassian products. Custom UI apps inherit modern security features to ensure high trust between Atlassian, developers, and users.

Custom UI is designed for complex use cases and increased developer flexibility. The UI kit is a more suitable option for simpler use cases. For more information on how to choose between custom UI and the UI kit, see User interface.

This page describes the main concepts behind custom UI and how these concepts are applied in a sample Forge app.

  • Custom UI iframe: Reference documentation for the Custom UI iframe that describes required permissions of the iframe.
  • Shared responsibility model: Understand your responsibilities when building and supporting a Forge app, and what responsibilities Atlassian takes care of.

Resources

A resource is a collection of static assets, which is hosted on and distributed by Atlassian cloud infrastructure.

To use custom UI, you need to provide a resource to an eligible module with the resource property. See Modules to see which modules are eligible for custom UI.

Consider the following example manifest.yml file:

1
2
modules:
  jira:issuePanel:
    - key: hello-world-panel
      resource: example-resource
      title: Hello world!
resources:
  - key: example-resource
    path: static/hello-world/build

This is the manifest declaration for a basic Jira issue panel using custom UI. In this example:

  • resource is a reference to a defined key in the resources object.
  • path is the relative path from the top-level directory of your Forge app to the directory of the static assets for the resource. It should contain the index.html entry point for the custom UI app; in this case, static/hello-world/build/index.html.

Consider an example index.html file saved in the root of the resource path:

1
2
<!DOCTYPE html>
<html>
  <body>
    <div>Hello, world!</div>
  </body>
</html>

In this example, index.html contains some text that's displayed to the user when they view the issue panel. The index.html file can include any valid HTML, JavaScript, and CSS, subject to security constraints.

The index.html file can also include other files from the same resource directory using relative URLs, such as JavaScript and CSS files, and images.

For example, to include an image at static/hello-world/build/images/image.png, the index.html looks like this:

1
2
<!DOCTYPE html>
<html>
  <body>
    <div>Hello, world!</div>
    <img src="./images/image.png"></img>
  </body>
</html>

See Resources reference documentation for more details.

Resource quotas

Static resources bundled with your app count against your Forge quotas. Resource quotas are consumed per deployment to your production environment; deployments to development and staging environments are unmetered. These quotas are refreshed weekly.

 Paid appsFree appsDistributed apps
 Per appPer appPer app
File capacity (weekly)150 MB75 MB75 MB
Files uploaded (weekly)500 files250 files250 files

For a detailed example of how resource quotas are calculated, see Calculate resources usage.

Icons

You can set an icon for any module that features an icon property. On both UI kit and custom UI implementations, you can bundle your icon files with other resources:

  1. Store your icon images in a location declared as a resource.
  2. Use the following syntax to reference the icon:
    1
    2
          icon: resource:<resource key>;<relative path to resource>
    

Icon files bundled with your code will count against your Forge resource quotas.

Consider the following manifest.yml excerpt. Here, we use the issue-panel.svg file located in static/hello-world/build/icons/ as our icon for the Jira issue panel:

1
2
modules:
  jira:issuePanel:
    - key: hello-world-panel
      title: Hello world!
      icon: resource:example-resource;icons/issue-panel.svg
resources:
  - key: example-resource
    path: static/hello-world/build

Alternatively, the icon property also supports an absolute URL to any self-hosted image file:

1
2
icon: https://example.com/icon.png

You can do this for either UI kit or custom UI apps.

Bridge

The custom UI bridge is a JavaScript API that enables UI Kit and custom UI apps to securely integrate with Atlassian products.

Option - 1:

To install the custom UI bridge using the @forge/bridge npm package:

  • Under static/<module-name> folder, run npm install -s @forge/bridge.

This installs the @forge/bridge dependency and saves it in package.json, which will allow importing @forge/bridge in the source using a bundler, such as Webpack.

Option - 2:

Start by creating a new app from one of the custom UI templates.

After you create a custom UI template:

  1. Go to static/<module-name> directory.

    Custom UI template can either create a folder with the module-name or hello-world.

  2. Run npm install && npm run build.

This will install @forge/bridge npm package and bundle the template static web application together with the custom UI bridge, into the static/<module-name>/build directory, which is used as the resource path in the Forge app's manifest.yml.

In the template, the bridge is used in static/<module-name>/src/App.js:

1
2
import { invoke } from "@forge/bridge";

invoke("exampleFunctionKey", { example: "my-invoke-variable" }).then(setData);

See Custom UI bridge reference documentation for the available bridge API methods.

Security

Custom UI apps are hosted by Atlassian. To help mitigate some common classes of security vulnerabilities, such as cross-site scripting (XSS) and data injection, all custom UI apps are served with a content security policy (CSP). For your custom UI app to work as expected, your users must be on a CSP-compatible browser.

Default limitations

By default, the CSP used in custom UI apps restricts some behavior. For example:

  • All scripts and assets used in your custom UI app must come from the same resource directory as your custom UI app. This means that you cannot use scripts or images from external sources, such as Google Analytics or Sentry, in your static assets. This is to help mitigate cross-site scripting vulnerabilities.
  • In a similar way, you cannot fetch APIs from your static assets. Instead, you must use the invoke method from the custom UI bridge to run an Atlassian-hosted backend FaaS function, where you may fetch from your desired APIs, and return the required data to the frontend.

If there is code in your custom UI app that violates the CSP, the app will not behave as expected, and an error will be shown in the browser console.

Custom content security and egress controls

Having visibility and control over the external systems that your app communicates and shares data with helps maintain the security of your app and your app users.

To enable this, we're providing a way to add permissions to share data with external resources, as well as to use custom Content Security Policies (CSP).

See add content security and egress controls to know how to set this up for your Forge app.

Inline styles

To include inline CSS in your app, follow the instructions on how to use custom content security policies.

Accessing static assets

Since the static assets of a custom UI app are distributed via a URL with a particular path that identifies your app, you should use relative paths when accessing these assets from your custom UI app. For example, instead of including an image at "/assets/image.png", you should use "./assets/image.png".

If you're getting 403 forbidden errors, ensure in the generated index.html file that all the static files source is a relative path.

See the following step-by-step tutorial to start building a custom UI app in Jira.

Viewport size

Custom UI apps in certain module types can be displayed in various sizes. You can configure the viewportSize property of a module in the app's manifest.yml file. See Modules to see which modules can be displayed in various sizes.

Look and feel

Your app's user experience is most effective when you keep its interface consistent with Atlassian's products. For guidance on doing so when using custom UI, refer to the Atlassian Design System.

Rate this page: