Last updatedFeb 24, 2020

Rate this page:

Forge UI

Forge UI is the framework for building dynamic and interactive app interfaces using Forge. This page describes the main concepts behind Forge UI. This page also demonstrates how these concepts are applied in an example Forge app.

Forge UI has three main concepts: components, hooks, and event handlers. You will need a basic knowledge of JavaScript to understand these concepts. If you've also used React before, these concepts are similar to the equivalent React concepts. However, be aware that they are not exactly the same. If you haven't used React before, then don't worry, we'll explain each concept in detail below.

Components

A component is an element that describes part of your app’s interface. To use components, you need to understand the following concepts:

  • Forge UI (FUI) components: FUI components are provided by the Forge platform. These include buttons, text, form fields, and more. Find the information about FUI components in the UI components reference documentation.
  • Function components: Function components are used to compose FUI components, in order to build an app. Every Forge app has one top-level function component that defines the whole interface.

Consider the following example:

1
2
3
4
5
import ForgeUI, { Text } from '@forge/ui';

const App = () => {
  return <Text content="Hello world!" />;
};

This is the code for a basic app that displays some text. In this example:

  • Text is the FUI component (see Text). FUI components are imported from the @forge/ui package.
  • App is the function component. It returns the Text FUI component. It also happens to be the top-level function component that defines the whole interface.

Components have a number of characteristics to consider when using them. The best way to understand them is to see them in action. Consider the following example app:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import ForgeUI, { Fragment, Text } from '@forge/ui';

const Issue = props => {
  return (
    <Fragment>
      <Text content={`Issue: ${props.issueKey}`} />
      <Text content={props.description} />
    </Fragment>
  );
};

const App = () => {
  return (
    <Fragment>
      <Text content="Current issue:" />
      <Issue issueKey="FRG-1" description="Example description for the FRG-1 issue." />
    </Fragment>
  );
};

export const run = render(<App/>);

This example app demonstrates the following:

  • Composable function components: Function components are composable, meaning they can return multiple components, including other function components. In the example above, the Issue function component is returned by the App function component.
  • Wrapping multiple components returned by a function component: Each function component must only return one top-level component. In order to to do this, you can use the Fragment component to wrap a list of components. In the example above, the Text and Issue components are wrapped in a single Fragment component, which is returned by the App component.
  • Syntax for components: Components are written using a syntax called JSX, which is similar to writing HTML. In the example above, Fragment is used within the App function by using angled brackets.
  • Props: Components can be passed data, known as props, to change what they render. In the example above, the content=”Current issue:” prop is passed to the Text component to tell it what string to show. For function components, props are passed as an object argument. You can see this above, where the props object is passed to the Issue component. The {props.issueKey} and {props.description} are then used to change what text is rendered.
  • The render() function: The render function turns the top-level component into an app, by transforming the app-as-a-functional-component into a function that is run on the Forge platform.

If you are a React developer, Forge UI components may look similar React components, particularly as they are both written in JSX. However, while React apps are rendered and executed on the client side, Forge apps run on a FaaS (function as a service) platform and are executed on the server side. Therefore, if a Forge app has any interactions that use developer-written code, those interactions will run server-side and incur a reasonable delay.

Hooks

Hooks make your components dynamic. They are special functions that enable you to update and use the state of your app. The state is a value that the component remembers and can be updated. Without hooks, you would not be able to access and manipulate the state of an app, as Forge apps run on a FaaS (function as a service) platform which is stateless. In addition to managing state, there are other hooks that let you access contextual data, such as the current user or Confluence page properties.

Hook functions are used inside function components and are registered to that component. The app remembers the state that is associated with that component. You can use or update this state via the hook. This also enables asynchronous callbacks in your app.

Consider the following example app. It extends the app shown in the Components section above, by adding a hook (useState) in the App function component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import ForgeUI, { Fragment, Text, useState } from '@forge/ui';
import api from '@forge/api';

const Issue = props => {
  return (
    <Fragment>
      <Text content={`Issue: ${props.issueKey}`} />
      <Text content={props.description} />
    </Fragment>
  );
};

const App = () => {
  const [issue, setIssue] = useState(async () => {
    const response = await api.asApp().requestJira('/rest/api/3/issue/{issueIdOrKey}');
    const issueData = response.text(); //... extract issueKey from response
    return issueData;
  });

  return (
    <Fragment>
      <Text content="Current issue:" />
      <Issue issueKey={issue.key} description={issue.description} />
    </Fragment>
  );
};

useState provides two key features:

  • Asynchronous callbacks: useState allows app developers to execute asynchronous callbacks.
  • State management: useState maintains the state and allows app developers to update and access it.

This example demonstrates the first feature. In the code above, the useState hook allows the initial state of the issue to be set asynchronously with data retrieved from the Jira REST API. The second feature is described in the next section, as it is easier to understand managing state when used with event handlers.

Hooks are special functions that must only be called at the top level from within function components. For example, don’t call hooks inside conditions, loops, or nested functions.

  • Forge UI hooks: Reference documentation for the hooks provided by the Forge platform. This includes other hooks that manage state as well as hooks that read context information about where the app is running.

Event handlers

Event handlers are functions that describe what to do when the user interacts with them. These should be familiar to you if you've used event handlers before (for example, in JavaScript). Combined with hooks, you can update state based on user interactions to build dynamic apps. Event handlers are only available for some interactive components, such as Button, where the component provides props to define the event handlers.

The following example app shows how an event handler works in Forge. It extends the app previously shown in the Hooks section above, by adding a button that lets the user close the current issue associated with the page. Also, the Issue component has been updated to dynamically render based on whether or not there is a currently open issue:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import ForgeUI, { Button, Fragment, Text, useState } from '@forge/ui';
import api from '@forge/api';

const Issue = props => {
  if (props.issueKey) {
    return (
      <Fragment>
        <Text content={`Issue: ${props.issueKey}`} />
        <Text content={props.description} />
      </Fragment>
    );
  } else {
    return <Text content="There is no open issue for this page" />;
  }
};

const App = () => {
  const [issue, setIssue] = useState(async () => {
    const response = await api.asApp().requestJira('/rest/api/3/issue/{issueIdOrKey}');
    const issueData = response.text(); // code to extract issue fields from response not shown here
    return issueData;
  });

  const handleCloseIssue = async () => {
    const issueKey = issue.key;
    const response = await api.asApp().requestJira('/rest/api/3/issue/{issueIdOrKey}');
    if (response.ok()) {
      setIssue({key: undefined, description: undefined});
    }
  };

  return (
    <Fragment>
      <Text content="Current issue:" />
      <Issue issueKey={issue.key} description={issue.description} />
      <Button text="Click" onClick={handleCloseIssue} />
    </Fragment>
  );
};

In this example, Button component has an onClick={handleCloseIssue} prop, where onClick is the event and the handleCloseIssue function is the event handler. Passing the handleCloseIssue function to this prop means that the function is called whenever the button is pressed.

The handleCloseIssue function is able to access the current issue.key (issue returned by the useState hook) and makes an API request to close the issue. If successful, setIssue is called to update the key and description of the current issue to undefined. This causes the Issue component to render the text, There is no open issue for this page.

Note how the useState hook makes the current state available (issue) and provides the function to update the state (setIssue). This is the state management feature of this hook that was described in the previous section.

  • Forge UI components: Reference documentation for the FUI components provided by the Forge platform. This includes interactive components that provide props to define event handlers.

You should now understand the basics of how event handlers work, how hooks work, and how they can be used together with components. These are the basic tools you need to build an app that is dynamic and interactive. To learn more about Forge UI, read the related pages that have been recommended throughout this page.

Rate this page: