Problem using useConfig of @forge/react in Custom UI

Currently, I’m not able to get the configuration of a macro to work in the development environment. Since it doesn’t work in my app, I used the example app confluence-macro-with-custom-configuration-custom-ui, which shows the same issue. forge/react is on the latest version 11.2.0, but every time I open the app I get the same error:

index.js:9 TypeError: Cannot read properties of null (reading 'useState')
    at t.useState (react.production.min.js:26:234)
    at t.useConfig (useConfig.js:17:45)
    at i (App.js:11:24)
const App = () => {
  const actualConfig = useConfig(); // problematic line

Following documentation i used to add the macro configuration https://developer.atlassian.com/platform/forge/add-configuration-to-a-macro-with-ui-kit/#custom-ui

At the moment, I have no idea how to solve this problem, since it’s already not working with the example apps. Does anyone have a hint or suggestion? Thanks in advance for the feedback!

Are you importing from React as well as @forge/react?

import React, { useState, useEffect } from 'react';
import ForgeReconciler, { useConfig } from '@forge/react';

I did that. Unfortunately, it didn’t help either. In the IDE, the actions useState, useEffect are marked as unused. The error occurs in react.production.js.

Here are the files and the errors in a bit more detail:

package.json

{
  "name": "confluence-macro-custom-ui-static",
  "version": "0.1.45",
  "private": true,
  "homepage": ".",
  "dependencies": {
    "@atlaskit/css-reset": "^6.6.2",
    "@forge/bridge": "4.5.1",
    "@forge/react": "^11.2.0",
    "react": "^16",
    "react-dom": "^16"
  },
  "devDependencies": {
    "react-scripts": "^5.0.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "eject": "react-scripts eject"
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

manifest.yml

modules:
  macro:
    - key: hello-world-2-hello-world
      resource: main
      resolver:
        function: resolver
      title: hello-world-2
      description: Inserts Hello world!
      config: true
  function:
    - key: resolver
      handler: index.handler
resources:
  - key: main
    path: static/hello-world-2/build
app:
  runtime:
    name: nodejs22.x
  id: ...

static/hello-world-2/index.jsx

import React from 'react';
import ReactDOM from 'react-dom';
import ForgeReconciler, { Label, Textfield, Text, useConfig, SectionMessage } from '@forge/react';

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

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

const App = () => {
  const actualConfig = useConfig();
  const config = actualConfig || defaultConfig;
  // Displaying the pet's name and age using the configuration values. SectionMessage component is optional.
  return (
    <>
      <Text>{config.name} is {config.age} years old.</Text>
      <SectionMessage title="You need to configure this macro" appearance="warning">
        <Text>
          While editing the page, select the macro, and click on the pencil icon
          to display configuration options.
        </Text>
      </SectionMessage>
    </>
  );
};


ReactDOM.render(
  <App />,
  document.getElementById('root')
);


ForgeReconciler.addConfig(<Config />);

Error trace in browser console

react-dom.production.min.js:209 TypeError: Cannot read properties of null (reading 'useState')
    at t.useState (react.production.min.js:26:234)
    at t.useConfig (useConfig.js:17:45)
    at i (index.jsx:23:24)
    at Zl (react-dom.production.min.js:153:146)
    at Ei (react-dom.production.min.js:261:496)
    at Tu (react-dom.production.min.js:246:265)
    at xu (react-dom.production.min.js:246:194)
    at yu (react-dom.production.min.js:239:172)
    at fu (react-dom.production.min.js:230:137)
    at Zu (react-dom.production.min.js:281:43)

react-dom.production.min.js:256 Uncaught TypeError: Cannot read properties of null (reading 'useState')
    at t.useState (react.production.min.js:26:234)
    at t.useConfig (useConfig.js:17:45)
    at i (index.jsx:23:24)
    at Zl (react-dom.production.min.js:153:146)
    at Ei (react-dom.production.min.js:261:496)
    at Tu (react-dom.production.min.js:246:265)
    at xu (react-dom.production.min.js:246:194)
    at yu (react-dom.production.min.js:239:172)
    at fu (react-dom.production.min.js:230:137)
    at Zu (react-dom.production.min.js:281:43)

You’re mixing UI Kit with Custom UI. Probably best to just start fresh, update the Forge CLI and run forge create then go through the options.

Or to fix current code…

Get rid of ReactDOM and use ForgeReconciler.render(<App />)

You’ll also need render: native in the macro manifest and perhaps a directory restructure to src/frontend/index.jsx

1 Like

Hey Markus, answers have nothing to do with your issue… “useConfig not working IN CUSTOM UI”…
Today I hit it and the anwwer is … not working with react@16 (which comes in template), but will work with react@18, hope it helps
Juan Arias

Hi Juan,

I’m currently facing the same issue. At the top level, I’m getting an any type for config, even though it should be generic—which unfortunately can’t be enforced properly when working with TypeScript in this context.

This doesn’t seem to be related to React 18. And if it were, it’s frustrating that there’s no official documentation stating that React 18 is a requirement—especially considering that React 18 still isn’t fully supported across Forge or Atlaskit components.

I only used the custom UI implementation. render: native is a Forge UI config, and with that, deployment doesn’t work at all, since the build path can only be a single JavaScript file. The implementation I’m using is like the one from the example.

I updated React with npm install @forge/react@latest --save and changed the versions in the package.json to React 18, but there’s no difference with version 18 either.
Do you have a simple example where it works?

Ah yeah I see the same issue doing forge create though they now seem to use Vite and are importing React+ReactDOM as externals.

So to fix that misconfiguration you either need to manually include the react JS files in the index.html

<script src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>

Or remove those externals in package.json and change the Vite config to:

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";

export default defineConfig({
  base: "./",
  plugins: [react()],
  build: {
    outDir: "build",
  },
});

They deprecated @forge/ui and so all my configuration pages that are provisioned in the backend stopped working, and now I’m having to create custom React configuration resources that don’t work properly because the examples are wrong. This feels like someone’s toy.