UI Kit components
UI Kit hooks
Forge bridge APIs
Jira bridge APIs
Upgrade UI Kit versions
Previous versions

This page is about the previous version of UI Kit.

We highly recommend upgrading to and utilizing the latest version. Get started with UI Kit's latest library of components to quickly build your user interface.

UI Kit 1 overview

UI Kit 1 lets you quickly and easily build a user interface for your app. It's made up of three main concepts: components, hooks, and event handlers.

Components are the visual elements that help you construct an intuitive and familiar user interface.

Hooks and event handlers enable your app to handle user interactions and return views dynamically from the server, where the UI Kit code is executed.

UI Kit 1 apps inherit modern security features to ensure high trust between Atlassian, developers, and users.

UI Kit 1 is designed for Forge apps with simpler use cases. Custom UI is a more suitable option for complex use cases. For more information on how to choose between the UI Kit and custom UI, see User interface.

This page describes the main concepts behind UI Kit 1 and how these concepts are applied in a sample Forge app. You'll 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're 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:

  • UI Kit 1 components: UI Kit 1 components are provided by the Forge platform. These include buttons, text, form fields, and more. See UI Kit 1 components reference documentation for more details.
  • Function components: Function components are used to compose UI Kit 1 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
import ForgeUI, { Text } from '@forge/ui';

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

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

  • Text is the UI Kit 1 component. UI Kit 1 components are imported from the @forge/ui package.
  • App is the function component. It returns the Text UI Kit 1 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
import ForgeUI, { render, Fragment, Text } from '@forge/ui';

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

const App = () => {
  return (
    <Fragment>
      <Image src="https://path/to/image.png" alt="Logo" />
      <Text>Current issue:</Text>
      <Issue issueKey="FRG-1" description="Example description for the FRG-1 issue." />
    </Fragment>
  );
};

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

This example app demonstrates the following:

If you are a React developer, UI Kit 1 components may look similar to 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.

  • UI Kit 1 components: Reference documentation for the UI Kit components provided by the Forge platform.
  • Shared responsibility model: Understand your responsibilities when building and supporting a Forge app, and what responsibilities Atlassian takes care of.

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
import ForgeUI, { Fragment, Text, useState } from '@forge/ui';
import api, { route } from '@forge/api';

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

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

  return (
    <Fragment>
      <Text>Current issue:</Text>
      <Issue issueKey={issue.key} description={issue.fields.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.

  • UI Kit 1 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
import ForgeUI, { Button, Fragment, Text, useState } from '@forge/ui';
import api, { route } from '@forge/api';

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

const App = () => {
  const issueIdOrKey = 'DOCS-1'; // key of the issue to be fetched
  const [issue, setIssue] = useState(async () => {
    const response = await api.asUser().requestJira(route`/rest/api/3/issue/${issueIdOrKey}`);
    const issueData = await response.json(); // code to extract issue fields from response not shown here
    return issueData;
  });

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

  return (
    <Fragment>
      <Text>Current issue:</Text>
      <Issue issueKey={issue.key} description={issue.fields.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.

  • UI Kit 1 components: Reference documentation for the UI kit 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 the UI Kit, read the related pages that have been recommended throughout this page.

Rate this page: