Frame
component is now available as part of Forge’s Early Access Program (EAP). To start using this EAP, sign up using the Forge EAP form.
Forge’s EAP offers experimental features to selected users for testing and feedback purposes. These features are unsupported and not recommended for use in production environments. They are also subject to change without notice.
For more details , see Forge EAP, Preview, and GA.
Frame component acts as a container for rendering static frontend applications, such as HTML, CSS, and JavaScript, ensuring seamless integration with the UI Kit.
The Frame component offers two methods for integrating custom UI resources within the UI Kit:
Frame
createFrame
.The first method, Frame
, is a straightforward approach that involves directly importing the Frame
component into your app. It provides flexibility in implementing desired user interfaces and supports communication with the main app through the Events API, allowing bidirectional and broadcast communication.
Alternatively, the createFrame
method introduces a react-like helper function that simplifies communication between the UI Kit and the Frame component. By allowing the passing of custom properties, it reduces the need for event-based communication, offering a streamlined approach for developers who prefer a React-like syntax. This method is particularly useful for applications where basic communication through properties suffices, enhancing ease of use and reducing complexity.
Setting up a resource for Frame
and createFrame
is similar to setting up for a Custom UI app, as documented on the Resources page.
Create a directory: In the root of the app directory, create a directory for the resource. For example, resources/my-frame-component
.
Add static frontend files: Include the static frontend files such as, HTML, CSS, JavaScript, images, and videos in the resource directory. The entry point should be an index.html
file. For React or Vue-based frontends, refer to the accessing static assets section in the Custom UI documentation.
Update manifest.yml: Add the resource key and path to the manifest.yml
file.
1 2hello-world-app ├── manifest.yml ├── resources │ └── my-frame-component │ └── index.html └── src ├── frontend │ └── index.jsx └── index.js
1 2modules: confluence:globalPage: - key: frame-example resource: main render: native title: Hello world! resources: - key: example-frame-resource # This is the resource key for the Frame component path: resources/my-frame-component - key: main # This is the resource key for the UI Kit part of the app path: src/frontend/index.jsx
To add the Frame
component to your app:
1 2import { Frame } from '@forge/react';
The Fame
component has the following properties that need to be considered:
Name | Type | Required | Usage | Description |
---|---|---|---|---|
resource | string | Yes | Frame component | This is the key of the resource to be loaded in the Frame . The resource must be defined in the app’s manifest.yml file. Refer to the guidelines below for defining a resource for Frame . |
1 2import React from 'react'; import ForgeReconciler, { Text, Frame } from '@forge/react'; const App = () => { return ( <> <Text>[UI Kit] Hello world!</Text> <Frame resource="example-frame-resource" /> </> ); }; ForgeReconciler.render( <React.StrictMode> <App /> </React.StrictMode> );
The Events API communication is both bidirectional and broadcast:
Bidirectional: Events can be sent from both the UI Kit and Frame
component using events.emit
.
Broadcast: A single event can be received by multiple targets (e.g., different instances or extensions of the same app) through the events.on
mechanism, as the Events API design enables communication among Custom UI extensions.
events.emit: This function sends data from either the UI Kit or Frame
component to the counterpart.
events.on: This function listens to and handles data transmitted via events.emit
.
The following example demonstrates how you can use the event.emit
function to send data from the UI Kit to the Frame
component:
1 2// This is the UI Kit part of the app, e.g., `src/frontend/index.jsx` for a Forge app import React, { useEffect } from 'react'; import ForgeReconciler, { Frame } from '@forge/react'; import { events } from '@forge/bridge'; const App = () => { useEffect(() => { // Send a message to the Frame component setTimeout(() => { events.emit('MY_FRAME_RESOURCE_DATA', { msg: 'hello' }); }, 2000); }, []); return <Frame resource="example-frame-resource" />; }; ForgeReconciler.render( <React.StrictMode> <App /> </React.StrictMode> );
The following example shows how you can use the event.on
function to receive data from the UI Kit in the Frame
component:
1 2// This is the Frame resource part of the app, e.g., `resources/frame-app/src/App.jsx` for a Forge app import React, {useEffect, useState } from 'react'; import { events } from "@forge/bridge"; function App() { const [msg, setMsg] = useState(''); useEffect(() => { let subscription = null; const registerMessage = async () => { subscription = await events.on('MY_FRAME_RESOURCE_DATA', ({ msg }) => { // This will be called whenever the message is sent from the UI Kit setMsg(msg); }); }; registerMessage(); return () => { if (subscription) { subscription.then(({ unsubscribe }) => unsubscribe()); } }; }, [setMsg]); return <b>{msg}</b>; }
To add the createFrame
helper function to your app:
1 2import { createFrame } from '@forge/react';
1 2function createFrame<CustomFrameProps extends Record<string, unknown>>( resource: string, arePropsEqual?: TArePropsEqual<CustomFrameProps> ): React.FC<CustomFrameProps>; type TArePropsEqual<CustomFrameProps extends Record<string, unknown>> = ( prevProps: CustomFrameProps, nextProps: CustomFrameProps ) => boolean;
The custom Frame
component that is created with the createFrame
helper function allows you to use custom properties:
Name | Type | Required | Usage | Description |
---|---|---|---|---|
CustomFrameProps | No | createFrame helper function | CustomFrameProps allows you to define custom properties for a Frame created using the createFrame helper function. CustomFrameProps should be an object where keys represent the prop names and values represent their types. When using TypeScript, define CustomFrameProps as a type parameter to createFrame for better type safety.
|
createFrame
Below is an example demonstrating how to use the createFrame
helper function to create a Frame
component:
1 2// This is the UI Kit part of the app, for example, `src/frontend/index.tsx` for a Forge app import React from 'react'; import ForgeReconciler, { createFrame } from '@forge/react'; // Define the custom properties type for the Frame component, // this is only applicable to TypeScript-based apps type TestFrameProps = { msg: string }; // Create a Frame component taking custom props by specifying: // 1. The target resource key (i.e., the standard resource prop in Frame component) // 2. The desired custom properties type definitions // (only applicable to TypeScript-based app) const TestFrame = createFrame<CustomFrameProps>('example-frame-resource'); const App = () => { return <TestFrame msg="hello" />; }; ForgeReconciler.render( <React.StrictMode> <App /> </React.StrictMode> );
For many Forge apps, basic communication through properties in a React-like approach is sufficient. The createFrame
helper facilitates this by allowing you to pass properties from the UI Kit to the Frame
component as simple React component properties, without needing to explicitly use events.emit
from the Events API.
The following shows how createFrame
can be leveraged to pass properties:
1 2// This is the UI Kit part of the app, for example, `src/frontend/index.tsx` for a Forge app import React from 'react'; import ForgeReconciler, { createFrame } from '@forge/react'; // Define the custom properties type for the Frame component, // this is only applicable to TypeScript-based apps type CustomFrameProps = { msg: string }; // Create a Frame component with custom props by specifying: // 1. The target resource key (i.e., the standard resource prop in Frame component) // 2. The desired custom properties type definitions // (only applicable to TypeScript-based app) const TestFrame = createFrame<CustomFrameProps>('example-frame-resource'); const App = () => { return <TestFrame msg="hello" />; }; ForgeReconciler.render( <React.StrictMode> <App /> </React.StrictMode> );
frame.onPropsUpdate
The frame.onPropsUpdate
helper allows Frame
resources to subscribe to component prop changes, enabling easy consumption of props sent from the UI Kit without needing to explicitly use events.on
from the Events API.
Below is an example of how frame.onPropsUpdate
can be used:
1 2// This is the Frame resource part of the app, for example, `resources/frame-app/src/App.tsx` for a Forge app import React from 'react'; import { view } from "@forge/bridge"; // Define the custom properties type for the Frame component, // this is only applicable to TypeScript-based apps type CustomFrameProps = { msg: string }; // Convert `view.frame.onPropsUpdate` to a standard React hook for React-based apps. const useFrameProps = <TProps,>() => { const [frameProps, setFrameProps] = React.useState<TProps | null>(null); useEffect(() => { let deregister = null; const registerPropsUpdate = async () => { deregister = await view.frame.onPropsUpdate<TProps>((frameProps) => { // Called whenever the props change in the custom Frame component created through `createFrame`. setFrameProps(frameProps); }); }; registerPropsUpdate(); return () => { if (deregister) { // Unsubscribe from handling property change events to ensure proper cleanup, as described in the [Events API documentation](https://developer.atlassian.com/platform/forge/apis-reference/ui-api-bridge/events/#unsubscribe). deregister(); } }; }, [setFrameProps]); return [frameProps !== null, frameProps]; }; function App() { const [isLoaded, frameProps] = useFrameProps<CustomFrameProps>(); if (!isLoaded) { return "Loading..."; } const { msg } = frameProps; return <b>{msg}</b>; }
To test your app locally with fast iteration, you can use the Forge tunnel to connect your local code with the app running in the development environment
1 2forge tunnel
To deploy your app, use the Forge deploy command.
1 2forge deploy
For the EAP release, support for the Frame
component has been enabled in the following modules:
Other modules of the Confluence, Jira, JSM, and Bitbucket products are supported, but since they're part of the Early Access Program (EAP), we haven't fully tested their modules yet, so we can't guarantee complete support at this moment.
Product | Module |
---|---|
Confluence | Macro |
Global Page | |
Jira | Issue Panel |
Global Page | |
Custom Field | |
Admin Page | |
Compass | Not Supported |
Frame
component for Jira modules. The support for these extension points is currently in progress, and is expected to be available after EAP.Frame
component can be rendered per module to minimize potential performance impact.Frame
component does not resize correctly within the application upon layout updates, we recommend checking and confirming that the sizing properties of the root container are defined using non-viewport-related units such as %
, px
, em
, and so on. This limitation is because the Frame
component's root container does not well support viewport-based relative sizing units like vh
and vw
.Rate this page: