About UI Kit 2
UI Kit 2 components
UI kit components
Product bridge APIs
Jira bridge APIs

This guide only applies to UI Kit 2 (Preview) apps. If your app is using UI kit, please follow this guide.

UI Kit 2 hooks

UI Kit 2 hooks are functions that let you manage the data you need to render your app. They can be added to your app's files.

useProductContext

This hook reads the context in which the component is currently running. Note that the context data is loaded asynchronously, so its output will be undefined while it is still loading.

Usage

To add the useProductContext hook to your app:

1
2
import { useProductContext } from "@forge/react";

Here is an example of an app that displays all its context information with useProductContext.

The app display on a Confluence page

1
2
import React from 'react';
import ForgeReconciler, { Code, Heading, Text, useProductContext } from '@forge/react';

const App = () => {
  const context = useProductContext();

  return (<>
    <Heading size="small">Product context</Heading>
    <Text>
      Module key from context:
      <Code>{context?.moduleKey}</Code>
    </Text>
  </>);
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Function signature

1
2
function useProductContext(): FullContext | undefined;

interface FullContext {
  accountId?: string;
  cloudId?: string;
  workspaceId?: string;
  extension: ExtensionData;
  license?: LicenseDetails;
  localId: string;
  locale: string;
  moduleKey: string;
  siteUrl: string;
  timezone: string;
}

interface ExtensionData {
  [k: string]: any;
}

interface LicenseDetails {
  active: boolean;
  billingPeriod: string;
  ccpEntitlementId: string;
  ccpEntitlementSlug: string;
  isEvaluation: boolean;
  subscriptionEndDate: string | null;
  supportEntitlementNumber: string | null;
  trialEndDate: string | null;
  type: string;
}

Arguments

None.

Returns

useConfig

This hook retrieves the configuration values for a macro. Note that the configuration data is loaded asynchronously, so its output will be undefined while it is still loading.

Use configuration to store general data, but not sensitive information. The configuration data is stored in plaintext, so other users and apps can access and modify the values.

Usage

To add the useConfig hook to your app:

1
2
import { useConfig } from "@forge/react";

Here is an example of accessing configuration for a Forge macro. Note that you'll need to add configuration to the Confluence macro module in order to configure the displayed values.

The app display on a Confluence page

1
2
import React from 'react';
import ForgeReconciler, { Heading, Text, TextField, useConfig } from '@forge/react';

const defaultConfig = { name: 'Unnamed Pet', age: '0' };

const App = () => {
  const config = useConfig() || defaultConfig;
  // Displaying a pet's name and age using the configuration values.
  return (
    <>
      <Heading>Content with configured values</Heading>
      <Text>"{config.name}" is "{config.age}" years old.</Text>
    </>
  );
};

// Function that defines the configuration UI for the pet's name and age
const Config = () => {
  return (
    <>
      <TextField name="name" label="Pet name" defaultValue={defaultConfig.name} />
      <TextField name="age" label="Pet age" defaultValue={defaultConfig.age} />
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

// Adding the Config function to the ForgeReconciler to allow for configuration changes
ForgeReconciler.addConfig(<Config />);

Function Signature

1
2
interface ExtensionConfiguration {
  [key: string]: any;
}

function useConfig(): ExtensionConfiguration | undefined;

Arguments

None.

Returns

  • ExtensionConfiguration: If the macro has been configured, this hook returns a dictionary containing the configuration key-value pairs. The keys are the name props given to the child components of the MacroConfig component. If the macro has not yet been configured, this hook returns undefined.

useContentProperty

This hook reads, writes, or updates the content properties in the Confluence page where the app is installed. Note that this hook is only for use on pages; to manage content properties on blog posts and other entities, use @forge/bridge's requestConfluence function to connect to the Confluence REST API.

When using this event, your Forge app must have permission from the site admin to access the data it provides within the event payload. The OAuth scope required are: read:page:confluence, write:page:confluence

Running the forge lint command picks up these required scopes.

Usage

To add the useContentProperty hook to your app:

1
2
import { useContentProperty } from "@forge/react";

Avoid calling useContentProperty multiple times in the same app, since their outputs are not synced.

Here is an example of an app that stores information in a content property with useContentProperty.

The app display on a Confluence page

1
2
import React from 'react';
import ForgeReconciler, { Button, Heading, Inline, useContentProperty } from '@forge/react';

const App = () => {
  const [number, setNumber, deleteNumber] = useContentProperty('number', '<Click me>');
  const setRandomInt = async () => {
    const randomInt = Math.floor(Math.random() * 10);
    await setNumber(randomInt);
  };
  return (
    <>
      <Heading size='medium'>Content Property</Heading>
      <Inline>
        <Button onClick={setRandomInt}>{`Random number: ${number}`}</Button>
        <Button onClick={async () => await deleteNumber()}>Delete</Button>
      </Inline>
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Here's another example that updates the content property based on the current value stored in the property.

The app display on a Confluence page

1
2
import React from 'react';
import ForgeReconciler, { Button, Heading, Inline, useContentProperty } from '@forge/react';

const App = () => {
  const [count, setCount, deleteCount] = useContentProperty('count', 0);
  const increaseCount = async () => await setCount((c) => (c+1));

  return (
    <>
      <Heading size='medium'>Content Property</Heading>
      <Inline>
        <Button onClick={increaseCount}>{`Clicks: ${count}`}</Button>
        <Button onClick={async () => await deleteCount()}>Delete</Button>
      </Inline>
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Function signature

1
2
function useContentProperty<V>(
  key: string,
  defaultValue: V
): [
  V,
  ((value: V | ((prevValue: unknown) => V), retries?: number) => Promise<V>),
  () => Promise<void>
];

Arguments

  • key: The key for the content property. The key is namespaced automatically and stored with a key of form forge-${localId}-${key}. Note that keys of the same name are not shared across different apps.
  • defaultValue: The default value to use if the content property does not exist yet.

Returns

  • An array of three elements:
    • The first element is the current value of the property (or default value if the property does not exist). Note that this value takes time to load, so it will initially be undefined before its actual value is loaded into this variable.

    • The second element is an asychronous function used to update the property. The update may run for multiple times per function call if the previous attempts fail (due to other updates). A second optional value specifies the number of retries to attempt (default is 2). There are two ways to use this:

      • Provide a new value, which will create or replace the property.
      • Provide an updater function, which takes the current value stored in the property and returns an updated value to store.

      When updating a property based on its previous state, make sure to pass in the calculation as an updater function. This ensures that its new value is calculated based on the most recent value in the cloud, rather than the cached value on the users' device.

    • The third element is an asychronous function that can be used to delete the property.

useSpaceProperty

This hook reads, writes, or updates the space properties in the Confluence page where the app is installed.

When using this event, your Forge app must have permission from the site admin to access the data it provides within the event payload. The OAuth scope required are: read:space:confluence, write:space:confluence

Running the forge lint command picks up these required scopes.

Usage

To add the useSpaceProperty hook to your app:

1
2
import { useSpaceProperty } from "@forge/react";

Avoid calling useSpaceProperty multiple times in the same app, since their outputs are not synced.

Here is an example of an app that stores information in a space property with useSpaceProperty.

The app display on a Confluence page

1
2
import React from 'react';
import ForgeReconciler, { Button, Heading, Inline, useSpaceProperty } from '@forge/react';

const App = () => {
  const [number, setNumber, deleteNumber] = useSpaceProperty('number', '<Click me>');
  const setRandomInt = async () => {
    const randomInt = Math.floor(Math.random() * 10);
    await setNumber(randomInt);
  };
  return (
    <>
      <Heading size='medium'>Space Property</Heading>
      <Inline>
        <Button onClick={setRandomInt}>{`Random number: ${number}`}</Button>
        <Button onClick={async () => await deleteNumber()}>Delete</Button>
      </Inline>
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Here's another example that updates the space property based on the current value stored in the property.

The app display on a Confluence page

1
2
import React from 'react';
import ForgeReconciler, { Button, Heading, Inline, useSpaceProperty } from '@forge/react';

const App = () => {
  const [count, setCount, deleteCount] = useSpaceProperty('count', 0);
  const increaseCount = async () => await setCount((c) => (c+1));

  return (
    <>
      <Heading size='medium'>Space Property</Heading>
      <Inline>
        <Button onClick={increaseCount}>{`Clicks: ${count}`}</Button>
        <Button onClick={async () => await deleteCount()}>Delete</Button>
      </Inline>
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Function signature

1
2
function useSpaceProperty<V>(
  key: string,
  defaultValue: V
): [
  V,
  ((value: V | ((prevValue: unknown) => V), retries?: number) => Promise<V>),
  () => Promise<void>
];

Arguments

  • key: The key for the space property. The key is namespaced automatically and stored with a key of form forge-${key}.
  • defaultValue: The default value to use if the space property does not exist yet.

Returns

  • An array of three elements:
    • The first element is the current value of the property (or default value if the property does not exist). Note that this value takes time to load, so it will initially be undefined before its actual value is loaded into this variable.

    • The second element is an asychronous function used to update the property. The update may run for multiple times per function call if the previous attempts fail (due to other updates). A second optional value specifies the number of retries to attempt (default is 2). There are two ways to use this:

      • Provide a new value, which will create or replace the property.
      • Provide an updater function, which takes the current value stored in the property and returns an updated value to store.

      When updating a property based on its previous state, make sure to pass in the calculation as an updater function. This ensures that its new value is calculated based on the most recent value in the cloud, rather than the cached value on the users' device.

    • The third element is an asychronous function that can be used to delete the property.

useIssueProperty

This hook reads, writes, or updates the issue properties in the Jira issue where the app is installed.

When using this event, your Forge app must have permission from the site admin to access the data it provides within the event payload. The OAuth scope required are: read:jira-work, write:jira-work

Running the forge lint command picks up these required scopes.

Usage

To add the useIssueProperty hook to your app:

1
2
import { useIssueProperty } from "@forge/react";

Avoid calling useIssueProperty multiple times in the same app, since their outputs are not synced.

Here is an example of an app that stores information in an issue property with useIssueProperty.

The app display on a Jira issue

1
2
import React from 'react';
import ForgeReconciler, { Button, Heading, Inline, useIssueProperty } from '@forge/react';

const App = () => {
  const [number, setNumber, deleteNumber] = useIssueProperty('number', '<Click me>');
  const setRandomInt = async () => {
    const randomInt = Math.floor(Math.random() * 10);
    await setNumber(randomInt);
  };
  return (
    <>
      <Heading size='medium'>Issue Property</Heading>
      <Inline>
        <Button onClick={setRandomInt}>{`Random number: ${number}`}</Button>
        <Button onClick={async () => await deleteNumber()}>Delete</Button>
      </Inline>
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Here's another example that updates the issue property based on the current value stored in the property.

The app display on a Jira issue

1
2
import React from 'react';
import ForgeReconciler, { Button, Heading, Inline, useIssueProperty } from '@forge/react';

const App = () => {
  const [count, setCount, deleteCount] = useIssueProperty('count', 0);
  const increaseCount = async () => await setCount((c) => (c+1));

  return (
    <>
      <Heading size='medium'>Issue Property</Heading>
      <Inline>
        <Button onClick={increaseCount}>{`Clicks: ${count}`}</Button>
        <Button onClick={async () => await deleteCount()}>Delete</Button>
      </Inline>
    </>
  );
};

ForgeReconciler.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

Function signature

1
2
function useIssueProperty<V>(
  key: string,
  defaultValue: V
): [
  V,
  ((value: V | ((prevValue: unknown) => V), retries?: number) => Promise<V>),
  () => Promise<void>
];

Arguments

  • key: The key for the issue property. The key is namespaced automatically and stored with a key of form forge-${key}.
  • defaultValue: The default value to use if the issue property does not exist yet.

Returns

  • An array of three elements:
    • The first element is the current value of the property (or default value if the property does not exist). Note that this value takes time to load, so it will initially be undefined before its actual value is loaded into this variable.

    • The second element is an asychronous function used to update the property. The update may run for multiple times per function call if the previous attempts fail (due to other updates). A second optional value specifies the number of retries to attempt (default is 2). There are two ways to use this:

      • Provide a new value, which will create or replace the property.
      • Provide an updater function, which takes the current value stored in the property and returns an updated value to store.

      When updating a property based on its previous state, make sure to pass in the calculation as an updater function. This ensures that its new value is calculated based on the most recent value in the cloud, rather than the cached value on the users' device.

    • The third element is an asychronous function that can be used to delete the property.

Migrate from UI kit to UI Kit 2 (Preview)

Not all hooks in UI kit exist in UI Kit 2.

UI kit implementations of standard react library hooks (useState, useEffect and useAction) can now be directly accessed from react instead (see Hooks API Reference – React). Note that the react equivalent of UI kit's useAction is useReducer, although usage of both is identical.

The useProductContext, useConfig, useContentProperty, useSpaceProperty and useIssueProperty hooks are available in our @forge/react package.

In addition, since the context/configuration/property values outputted by the @forge/react hooks take time to load, they will not be immediately available upon app mounting; i.e. these values will initially be undefined before they are loaded with actual values.

useState, useEffect, useAction (useReducer)

UI kit

1
2
import ForgeUI, { useState, useEffect, useAction, Text } from '@forge/ui';

const App = () => {
  const [count, setCount] = useState(0);

  return (
    <Text>Count: {count}</Text>
  );
}

UI Kit 2

1
2
import React, { useState, useEffect, useReducer } from 'react';
import { Text } from '@forge/react';

const App = () => {
  const [count, setCount] = useState(0);

  return (
    <Text>Count: {count}</Text>
  );
};

Rate this page: