Last updated Aug 29, 2023

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

UI kit hooks

UI kit hooks are functions that let you manage the data you need to render your app. They can be added to your app's index.jsx file.

useState

This hook adds and updates local state to a component.

Usage

Here is an example of useState to create a counter app.

1
2
import ForgeUI, { useState, Button, Macro, render } from '@forge/ui';

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <Button
      text={`Count is ${count}`}
      onClick={() => {
        setCount(count + 1);
      }}
    />
  );
};

export const run = render(<Macro app={<App />} />);

Function signature

1
2
function useState<V>(
  initialValue: V | (() => V) | (() => Promise<V>)
): [V, (newState: V) => void];

Arguments

  • initialValue: The initial state of the hook. This can be a value, a function that returns a value or a function that returns a Promise. If a Promise is returned, the resolved value of the Promise is the initial state.

Returns

  • An array of two elements. The first element is the current state of the hook. The second value is a function used to update the state. The argument of this function is the value of the new state.

useAction

This hook manages local state in a similar way to the useState hook, providing a more complex reducer argument to update state.

Usage

Here is an example of useAction to create a counter app.

1
2
import ForgeUI, { useAction, Button, Macro, render } from '@forge/ui';

const App = () => {
  const [count, setCount] = useAction(
    (currentCount, step) => currentCount + step,
    0
  );
  return (
    <Button
      text={`Count is ${count}`}
      onClick={() => {
        // what we call "setCount" with will be "step" in reducer
        setCount(1);
      }}
    />
  );
};

export const run = render(<Macro app={<App />} />);

Function signature

1
2
function useAction<V, P>(
  reducer: (currentState: V, payload: P) => V | Promise<V>,
  initialValue: V | (() => V) | (() => Promise<V>)
): [V, (payload?: P) => void];

Arguments

  • reducer: A function that describes how to update the state. The reducer gets passed the current state and the payload. The value returned by this function becomes the new state. If a Promise is returned by the reducer, the resolved value of the Promise is the new state.
    • currentState: The current value of the hook.
    • payload: The data that the function used to update the state was called with.
  • initialValue: The initial state of the hook. This can be a value, a function that returns a value or a function that returns a Promise. If a Promise is returned, the resolved value of the Promise is the initial state.

Returns

  • An array of two elements. The first element is the current state of the hook. The second value is a function used to update the state. The arguments you call this function with will be passed to the second argument of the reducer function.

useEffect

This hook executes a given function when one of the variables in the hook's second argument, which is the dependency array, changes its value.

Usage

Here is an example of useEffect to create a counter app.

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

const sendLog = async () => Promise.resolve('send!');

const LogData = ({ counter }) => {
  const [logSend, setLogSend] = useState();

  useEffect(async () => {
    await sendLog();

    setLogSend(Date.now());
  }, [counter]);

  return <Text>Last log: {logSend}</Text>;
};

const App = () => {
  const [count, setCount] = useState(0);
  return (
    <Fragment>
      <Button
        text={`Count is ${count}`}
        onClick={() => {
          setCount(count + 1);
        }}
      />
      <LogData counter={count} />
    </Fragment>
  );
};

export const run = render(<Macro app={<App />} />);

Function signature

1
2
function useEffect = (
  onChange: () => void | Promise<void>,
  dependencies: (boolean | string | number | object)[]
): void;

Arguments

  • onChange: A function containing a side effect. A side effect can include network requests and setting of app state. The function can be synchronous with no value returned, or may return a void promise. The function always runs once initially.
  • dependencies: An array of values that are tracked and compared across component renders. If one of the values change, the onChange function is executed. The values included in the dependency array must be a string, number or boolean, or an object or array of these types.

Returns

This hook doesn't return anything.

useProductContext

This hook reads the context in which the component is currently running.

For Bitbucket, the ProductContext would contain an extra field workspaceId. This is the Bitbucket workspace UUID of the application on which the extension is working.

Usage

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

1
2
import ForgeUI, { useProductContext, Text, Macro, render } from '@forge/ui';

const App = () => {
  const context = useProductContext();
  return <Text>All info about my context: {JSON.stringify(context)}</Text>;
};

export const run = render(<Macro app={<App />} />);

Function signature

1
2
function useProductContext(): ProductContext;

interface ProductContext {
  accountId?: string;
  accountType?: AccountType;
  cloudId?: string;
  workspaceId?: string;
  contentId?: string;
  localId?: string;
  spaceKey?: string;
  environmentId?: string;
  environmentType?: string;
  installContext?: string;
  platformContext?: PlatformContext;
  extensionContext?: ExtensionContext;
  license?: LicenseDetails;
}

type AccountType = 'licensed' | 'unlicensed' | 'customer' | 'anonymous';

interface PlatformContext {
  type: string;
}

interface JiraContext extends PlatformContext {
  type: 'jira';
  issueId: string;
  issueKey: string;
  issueType: string;
  projectId: string;
  projectKey: string;
  projectType: string;
}

interface ExtensionContext {
  type: string;
}

interface DashboardGadgetExtensionContext extends ExtensionContext {
  type: 'dashboardGadget';
  gadgetConfiguration: { [string]: string | boolean | number };
}

interface LicenseDetails {
  isActive: boolean;
}

Returns

  • ProductContext: An object containing contextual information about the current environment in which the component is running; all values are optional, depending on where the component is used.

    • cloudId: The ID of the application on which the extension is working, for example the ID of a Jira or Confluence instance.
    • workspaceId: The workspace ID of the application on which the extension is working, for example the ID of a Bitbucket workspace.
    • accountId: The Atlassian ID or JSM Customer ID of the user that interacted with the component.
    • accountType: The account type of the user that interacted with the component. Note, this field is mainly intended to be used in components that permit access by users without corresponding product license.
    • contentId: The ID of the piece of content in which this component appears.
    • localId: The unique ID for this instance of this component in the content.
    • spaceKey: The space in which the content is located (Confluence only).
    • environmentId: The unique ID of the environment where the component is deployed.
    • environmentType: The name of the environment where the component is deployed.
    • installContext: The ARI identifying the cloud or product context of this component installation.
    • platformContext: Contextual information about the current environment that depends on where the component is being used (currently, Jira only).
    • extensionContext: Contextual information about the current environment that depends on the extension being used.
    • license: Contains information about the license of the app. Note: this field is only present for paid apps in the production environment. license is undefined for free apps, apps not listed on the Atlassian Marketplace, and apps in development and staging environments. See the LicenseDetails type for what information is available.
  • JiraContext: Contextual information returned when the component is running in Jira.

    • type: The product type (always 'jira').
    • issueId: The ID of the issue that the component is on.
    • issueKey: The key of the issue that the component is on.
    • issueType: The name of the issue type that the component is on.
    • issueTypeId: The ID of the issue type that the component is on.
    • projectKey: The key of the project that the component is on.
    • projectId: The ID of the project that the component is on.
    • projectType: The name of the project type that the component is on.
  • DashboardGadgetExtensionContext: Contextual information returned by the jira:dashboardGadget module.

    • type: The extension type (always 'dashboardGadget').
    • gadgetConfiguration: The stored Form values from the dashboardGadgetEdit module. For example, { "name": "John" }.

useConfig

This hook retrieves the configuration values for a macro.

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

Here is an example of accessing configuration for a Forge macro.

1
2
import ForgeUI, {
  useConfig,
  Text,
  TextField,
  Macro,
  MacroConfig,
  render,
} from '@forge/ui';

const App = () => {
  // Retrieve the configuration
  const config = useConfig();

  // Use the configuration values
  return (
    <Text>
      {config.name} is {config.age} years old.
    </Text>
  );
};

export const run = render(<Macro app={<App />} />);

// Function that defines the configuration UI
const Config = () => {
  return (
    <MacroConfig>
      <TextField name="name" label="Pet name" />
      <TextField name="age" label="Pet age" />
    </MacroConfig>
  );
};

export const config = render(<Config />);

Function Signature

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

function useConfig(): ExtensionConfiguration;

Arguments

None

Returns

  • ExtensionConfiguration: A dictionary containing the configuration key-value pairs. The keys are the name props given to the child components of the MacroConfig component.

useContentProperty

This hook reads, writes, or updates the content 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 is documented under each product event.

Running the forge lint command picks up these required scopes.

Usage

You'll need to add the @forge/ui-confluence to your app's dependencies. Run this command in the directory:

1
2
npm install @forge/ui-confluence

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

1
2
import ForgeUI, { Button, Macro, render } from '@forge/ui';
import { useContentProperty } from '@forge/ui-confluence';

const App = () => {
  const [count, setCount] = useContentProperty('count', 0);
  return (
    <Button
      text={`Count is ${count}`}
      onClick={async () => {
        // replace current value (regardless of if changed by someone else)
        await setCount(count + 1);
      }}
    />
  );
};

export const run = render(<Macro app={<App />} />);

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

1
2
import ForgeUI, { Button, Macro, render } from '@forge/ui';
import { useContentProperty } from '@forge/ui-confluence';

const App = () => {
  const [count, setCount] = useContentProperty('count', 0);
  return (
    <Button
      text={`Count is ${count}`}
      onClick={async () => {
        // update current value (avoids overwriting someone else's change)
        await setCount((prevCount) => prevCount + 1);
      }}
    />
  );
};

export const run = render(<Macro app={<App />} />);

Function signature

1
2
function useContentProperty<V>(
  key: string,
  defaultValue: V
): [
  V,
  ((value: V | ((prevValue: V) => 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}.
  • 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 content property (or default value if the content property does not exist).
    • The second element is a function used to update the content property. There are two ways to use this:
      • Provide a new value, which will create or replace the content property.
      • Provide an updater function, which takes the current value stored in the content property and returns an updated value to store. The update may be called multiple times per function call if the update fails (due to other updates). A second optional value specifies the number of retries to attempt (default is 2).
    • The third element is a function that can be used to delete the space property.

useIssueProperty

This hook reads, writes, or updates the issue properties for the Jira issue that the component is on.

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 is documented under each product event.

Running the forge lint command picks up these required scopes.

Usage

Add @forge/ui-jira to your app's dependencies by running this command in the root directory of your app:

1
2
npm install @forge/ui-jira

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

1
2
import ForgeUI, { render, IssuePanel, Text, Button } from '@forge/ui';
import { useIssueProperty } from '@forge/ui-jira';
const App = () => {
  const [count, setCount] = useIssueProperty('counter', 1);
  return (
    <IssuePanel>
      <Text>Current value {count}</Text>
      <Button
        text="Add one (modify)"
        onClick={async () => {
          await setCount(count + 1);
        }}
      />
    </IssuePanel>
  );
};
export const run = render(<App />);

Arguments

  • key: The key for the issue property. The key is namespaced automatically and stored with a key which has the format, 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 issue property. If the issue property does not exist, this element will be the default value.
    • The second element is a function used to update the issue property, which is used in two ways:
      • Provides a new value that creates or replaces the issue property.
      • Provides an updater function that takes the current value stored in the issue property and returns an updated value to store. The update may be called multiple times per function call if the update fails (for example, due to other updates).
    • The third element is a function used to delete the issue 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 is documented under each product event.

Running the forge lint command picks up these required scopes.

Usage

You'll need to add the @forge/ui-confluence to your app's dependencies (0.2.5+). Run this command in the directory:

1
2
npm install @forge/ui-confluence

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

1
2
import ForgeUI, { Button, Macro, render } from '@forge/ui';
import { useSpaceProperty } from '@forge/ui-confluence';

const App = () => {
  const [count, setCount] = useSpaceProperty('space-wide-count', 0);
  return (
    <Button
      text={`Count is ${count}`}
      onClick={async () => {
        // replace current value (regardless of if changed by someone else)
        await setCount(count + 1);
      }}
    />
  );
};

export const run = render(<Macro app={<App />} />);

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

1
2
import ForgeUI, { Button, Macro, render } from '@forge/ui';
import { useSpaceProperty } from '@forge/ui-confluence';

const App = () => {
  const [count, setCount] = useSpaceProperty('space-wide-count', 0);
  return (
    <Button
      text={`Count is ${count}`}
      onClick={async () => {
        // update current value (avoids overwriting someone else's change)
        await setCount((prevCount) => prevCount + 1);
      }}
    />
  );
};

export const run = render(<Macro app={<App />} />);

Function signature

1
2
function useSpaceProperty<V>(
  key: string,
  defaultValue: V
): [
  V,
  ((value: V | ((prevValue: V) => 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 which has the format, 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 space property (or default value if the space property does not exist).
    • The second element is a function used to update the space property. There are two ways to use this:
      • Provide a new value, which will create or replace the space property.
      • Provide an updater function, which takes the current value stored in the space property and returns an updated value to store. The update may be called multiple times per function call if the update fails (due to other updates). A second optional value specifies the number of retries to attempt (default is 2).
    • The third element is a function that can be used to delete the space property.

Rate this page: