I’m implementing a custom field using Forge Custom UI, specifically for the edit view experience. With the recent changes to the isInline
attribute, I now need to manually render a modal dialog to display the custom field form.
As per the documentation, the recommended approach for Custom UI apps is to open the field form inside a modal using the Forge Modal bridge API.
I’m attempting to open the modal from within the same resource where my custom field form component is implemented. However, when the modal opens, it simply shows a “No data” message, and my form component is rendered inline outside the modal (screenshot below):
Here’s a simplified version of the implementation inside my App.js
:
import React, { useEffect, useState, useCallback } from "react";
import { Modal, view } from "@forge/bridge";
import { EditView } from "./components/EditView";
import {Box, xcss} from '@atlaskit/primitives'
import Spinner from '@atlaskit/spinner';
function App() {
const [extensionData, setExtensionData] = useState(null);
useEffect(() => {
view.getContext().then(({ extension }) => {
setExtensionData(extension);
const modal = new Modal({
onClose: handleClose,
size: 'medium',
});
modal.open();
console.log("extensionData =>", extension);
});
}, []);
// Handle modal close
const handleClose = (payload) => {
console.log('Modal closed with payload:', payload);
};
if (!extensionData) {
return (
<Box>
<Spinner size="large" label="Loading" />
{"Loading..."}
</Box>
);
}
return (
<Box>
<EditView extensionData={extensionData} />
</Box>
);
}
export default App;
However, when I refactor this to use a separate resource (defined in the manifest.yml
) for the modal and launch the form via the resource
option in the Modal
constructor, everything works correctly and the modal renders as expected.
What works:
manifest.yml
jira:customField:
- key: my-custom-field
name: My Custom Field
type: object
formatter:
expression: "`Name: ${value.myAttribute.name} Role: ${value.myAttribute.role}`"
export: true
schema:
properties:
myAttribute:
name: string
role: string
edit:
resource: edit
isInline: true
experience:
- "issue-create"
- "issue-transition"
- "issue-view"
resources:
- key: edit
path: static/custom-field-edit/build
- key: modal
path: static/modal/build
modal resource’s App.js
:
import React, { useState, useEffect } from "react";
import { view, Modal } from "@forge/bridge";
const App = () => {
useEffect(() => {
const openModal = async () => {
try {
const { extension } = await view.getContext();
const FieldModal = new Modal({
resource: "edit",
onClose: (payload) => {
console.log("onClose called with", payload);
},
size: "xlarge",
context: {
fieldExtension: extension,
},
});
FieldModal.open();
} catch (err) {
console.error("Error opening modal:", err);
}
};
openModal();
}, []);
return null;
}
export default App;
custom-field-edit resource’s App.js
:
function App() {
const [extensionData, setExtensionData] = useState(null);
useEffect(() => {
view.getContext().then(({ extension }) => {
setExtensionData(extension?.modal?.fieldExtension);
});
}, []);
if (!extensionData) {
return (
<Box>
<Spinner size="large" label="Loading" />
{"Loading..."}
</Box>
);
}
return (
<>
<Box>
<EditView extensionData={extensionData} />
</Box>
</>
);
}
export default App;
Question
Is it possible to open a modal from within the same Custom UI resource where the form is implemented?
If yes, what is the correct way to render a modal within the same resource, so that my component appears inside the modal and not inline?
Or is it a requirement to split the modal and form into two different resources for this to work correctly?