---
title: Creating a modal - Client-side Extensions
platform: server
product: clientside-extensions
category: devguide
subcategory: introduction
date: '2024-09-24'
---

# Creating a modal

{{% note %}}
This is a continuation of the work started in [4. Custom HTML content](/server/framework/clientside-extensions/guides/introduction/custom-HTML-content/).
{{% /note %}}

Modals can be complicated to create since generally you'll need to use an external library, and then modify its design to match the product you're creating the modals for.

With Client-side Extensions (CSE), you can use an extension type called **Modal** that lets you create a modal dialog that works well with your product, and you can focus on your feature instead.

## Modal extension

To create the modal extension, you need to use the `ModalExtension` factory. The CSE runtime will then use the `onAction` method
to inject a [Modal API](/server/framework/clientside-extensions/reference/api/extension-api/modal-api/) object when the modal is ready for you
to render the content in.

{{% note %}}
Remember that the `onAction` method behaves differently for each extension type. For more info, see [extension API reference](/server/framework/clientside-extensions/reference/api/extension-factories).
{{% /note %}}

## Rendering your content inside a modal

The modal API has the same `onMount`/`onUnmount` methods as panels to render your content, but also has some modal specific methods.

One of the modal specific APIs is `setTitle` that allows you to specify a title in the modal header.

### Create a modal extension for the pull request diff toolbar

You're now going to create a modal extension that opens after clicking a button in the pull request `diff` toolbar.

In the `/src/my-app/extensions/first-extension.js` file:

1. Use the `diff` toolbar extension point: `bitbucket.ui.pullrequest.diff.toolbar`.
2. Use the label attribute to add a text to the button that will open your modal.
3. Import `ModalExtension` from `@atlassian/clientside-extensions`, and use its factory to create a modal extension.
4. Use the `onAction` to get a modal API object.
5. Use the modal API to set a title.
6. Use the modal API to render your content inside the modal body.

```js
// #/src/my-app/extensions/first-extension.js
import { ModalExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point bitbucket.ui.pullrequest.diff.toolbar
 */
export default ModalExtension.factory((extensionAPI, context) => {
    return {
        label: 'Click to open a modal',
        onAction: (modalAPI) => {
            const getContent = () => `
                <p>And some content inside the modal too.</p>
            `;

            modalAPI.setTitle('Look, a Modal!');

            modalAPI.onMount((container) => {
                container.innerHTML = getContent();
            });

            modalAPI.onUnmount((container) => {
                container.innerHTML = '';
            });
        },
    };
});
```

## Modal actions

The modal API provides a method called `setActions` that allows you to render action buttons in your modal footer, and execute
arbitrary JavaScript when they are clicked.

You can also close the modal after executing an action by using `closeModal`.

### Add action buttons to your modal

Modify your modal extension to have a pair of actions. One of them should modify your modal content, and the other close the modal when clicked.

In the `/src/my-app/extensions/first-extension.js` file:

1. Define two actions for your modal using `setActions`.
2. The first action should keep count of the times it's been clicked, and show it in the modal content.
3. The second action should close the modal dialog when clicked.

```js
// #/src/my-app/extensions/first-extension.js
import { ModalExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point bitbucket.ui.pullrequest.diff.toolbar
 */
export default ModalExtension.factory((extensionAPI, context) => {
    return {
        label: 'Click to open a modal',
        onAction: (modalAPI) => {
            let count = 0;

            const getContent = () => `
                <p>The primary button has been clicked ${count} times.</p>
            `;

            modalAPI.setTitle('Look, a Modal!');

            modalAPI.onMount((container) => {
                container.innerHTML = getContent();

                // setting the actions of the modal
                modalAPI.setActions([
                    {
                        text: 'Primary',
                        onClick: () => {
                            count++;
                            container.innerHTML = getContent();
                        },
                    },
                    {
                        text: 'Close',
                        onClick: () => modalAPI.closeModal(),
                    },
                ]);
            });

            modalAPI.onUnmount((container) => {
                container.innerHTML = '';
            });
        },
    };
});
```

## Using custom content with React

Client-side Extensions (CSE) provides a utility that makes it easier to use React with the **Modal** extension. For more info, see [Rendering elements as React](/server/framework/clientside-extensions/reference/api/extension-api/render-element-as-react/).

## Recap

You've learned:

-   How to use a modal created by CSE and render your feature in it.
-   How to add actions to your modal extension.
-   How to programmatically close your modal extension.

{{% tip %}}
Make sure to check the [modal API reference](/server/framework/clientside-extensions/reference/api/extension-api/modal-api/) to explore more things you can do with modals.
{{% /tip %}}
