---
title: CSE webpack plugin - Client-side Extensions
platform: server
product: clientside-extensions
category: reference
subcategory: webpack
date: '2024-09-24'
---

# Annotations

The provided webpack plugin uses annotations in comments to gather information about the extension, and generate the XML for you.

## Supported annotations

<table>
    <colgroup>
        <col width="30%" />
        <col width="10%" />
        <col width="60%" />
    </colgroup>
    <thead>
        <tr class="header">
            <th>Name</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>@clientside-extension</code> <strong>*</strong></td>
            <td><code>-</code></td>
            <td>Indicates that the next function is an extension factory to be consumed by the webpack plugin.</td>
        </tr>
        <tr>
            <td><code>@extension-point</code> <strong>*</strong></td>
            <td><code>string</code></td>
            <td>Defines the location where the extension will be rendered.</td>
        </tr>
        <tr>
            <td><code>@weight</code></td>
            <td><code>number</code></td>
            <td>
                <p>Determines the order in which the extension appears respect to others in the same location.</p>
                <p>Extensions are displayed top to bottom or left to right in order of ascending weight.</p>
            </td>
        </tr>
        <tr>
            <td><code>@condition</code></td>
            <td><code>string | Condition, UrlReadingCondition</code></td>
            <td>
                <p>Defines one or multiple conditions that must be satisfied for the extension to be displayed.</p>
                <p>The conditions are evaluated on the server, and created with Java.</p>
                <p>If one of the conditions is not met, the code of the extension won't be loaded in the client.</p>
                <p>For more information about the conditions please refer to the <a href="/server/framework/atlassian-sdk/web-section-plugin-module/#condition-and-conditions-elements">examples of Web items documentation</a>.</p>
            </td>
        </tr>
    </tbody>
</table>

<p><strong>* required</strong></p>

## Deprecated annotations

The following annotations should no longer be used

<table>
    <colgroup>
        <col width="25%" />
        <col width="25%" />
        <col width="25%" />
        <col width="25%" />
    </colgroup>
    <thead>
        <tr class="header">
            <th>Name</th>
            <th>Type</th>
            <th>Deprecated since</th>
            <th>Planned removal</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>@label</code></td>
            <td><code>string</code></td>
            <td align="right">2.0</td>
            <td align="right">3.0</td>
        </tr>
        <tr>
            <td><code>@link</code></td>
            <td><code>string</code></td>
            <td align="right">2.0</td>
            <td align="right">3.0</td>
        </tr>
    </tbody>
</table>

Instead of specifying the following as annotations it is recommended to provide these as attributes at runtime:

```ts
import { LinkExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @weight 100
 */
export default LinkExtension.factory((api) => {
    return {
        label: 'My Link-Extension',
        url: '/my-link-extension',
    };
});
```

### Supported <code>PageExtension</code> annotations

The list of additional annotation that can be used with [`PageExtension`]. Refer to the [`PageExtension` API](/server/framework/clientside-extensions/reference/api/extension-factories/page/) to read more details about the supported annotations.

<table>
    <colgroup>
        <col width="30%" />
        <col width="10%" />
        <col width="60%" />
    </colgroup>
    <thead>
        <tr class="header">
            <th>Name</th>
            <th>Type</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td><code>@page-url</code> <strong>*</strong></td>
            <td><code>string</code></td>
            <td>
                <p>Defines an url of the web page. The page will be accessible at this url prefixed with <code>/plugins/servlet/&lt;&lt;page-url&gt;&gt;</code></p>
                <p><strong>Example</strong>: Using <code>@page-url /labels</code> will register the page at <code>/plugins/servlet/labels</code> URL.</p>
            </td>
        </tr>
        <tr>
            <td><code>@page-title</code> <strong>*</strong></td>
            <td><code>string</code></td>
            <td>Defines a title of the web page. The value can be either a raw string or a property key than will be translated.</td>
        </tr>
        <tr>
            <td><code>@page-decorator</code></td>
            <td><code>string</code></td>
            <td>
                <p>A custom page decorator. The default value is <code>atl.general</code>. To read more about page decorators <a href="/server/framework/atlassian-sdk/using-standard-page-decorators">refer to the documentation</a>.</p>
                <p>List of built-in decorators supported by all products:</p>
                <ul>
                    <li><code>atl.admin</code></li>
                    <li><code>atl.general</code></li>
                    <li><code>atl.popup</code></li>
                    <li><code>atl.userprofile</code></li>
                </ul>
            </td>
        </tr>
        <tr>
            <td><code>@page-data-provider</code></td>
            <td><code>string</code></td>
            <td>
                <p>A page data provider Java class. Page data providers can be used to provide a custom set of a server-side data into your browser page extension.</p>
                <p>To read more about the page data providers check the usage section.</p>
                <p><strong>Example</strong>: <code>@page-data-provider com.example.plugin.MyDataProvider</code></p>
            </td>
        </tr>
    </tbody>
</table>

<p><strong>* required for <code>PageExtension</code></strong></p>

## Keywords

<table>
    <colgroup>
        <col width="20%" />
        <col width="80%" />
    </colgroup>
    <thead>
        <tr class="header">
            <th>Name</th>
            <th>Description</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>$key</td>
            <td>When present in any annotation, $key will be replaced with the extension key generated by the CSE webpack plugin.</td>
        </tr>
    </tbody>
</table>

## Usage notes

### 1. Define a client-side extension, and the extension location to be rendered in

```ts
import { LinkExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 */
export default LinkExtension.factory(/*...*/);
```

### 2. Specify a weight

```ts
import { LinkExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @weight 100
 */
export default LinkExtension.factory(/*...*/);
```

### 3. Using the `page-*` annotations

The `page-*` annotations can be used to create a custom web and render a navigation link in the product UI.

```ts
/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @page-url /my-admin-page
 * @page-title "My admin page"
 * @page-decorator atl.admin
 */
export default PageExtension.factory((container) => {
    container.innerHTML = '<div>Very secure page!</div>';
});
```

Refer to the [`PageExtension` API](/server/framework/clientside-extensions/reference/api/extension-factories/page/) to read more details about the supported annotations.

<!-- prettier-ignore-start -->
### 4. Using $key keyword
<!-- prettier-ignore-end -->

For those cases where you need to know the value of the extension key and use it in the annotations, you can make use of the `$key` keyword.
CSE webpack plugin will replace it with the actual value of the key that the plugin generates for your extension.

```ts
import { PageExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @page-url /my-admin-page?q=$key
 * @page-title "My admin page"
 */
export default PageExtension.factory((container) => {
    container.innerHTML = '<div>Very secure page!</div>';
});
```

### 5. Define a condition

The `@condition` annotation allows you to define one or multiple conditions that must be satisfied for the extension to be displayed.
These conditions are evaluated on the server and are implemented in Java. They are used for determining if the extension should be downloaded and rendered by the client. For compatibility reasons, the condition class needs to implement both `com.atlassian.plugin.web.Condition` and `com.atlassian.webresource.spi.condition.UrlReadingCondition` interfaces, and both implementations should yield the same result.

For more information about the condition's usage please refer to the [examples of Web items documentation](https://developer.atlassian.com/server/framework/atlassian-sdk/web-section-plugin-module/#condition-and-conditions-elements) and check the [documentation of `conditionMap` option from `atlassian-webresource-webpack-plugin`](https://www.npmjs.com/package/atlassian-webresource-webpack-plugin#conditionmap-optional).

```ts
import { LinkExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @condition class com.atlassian.cse.demo.RandomCondition
 */
export default LinkExtension.factory(/*...*/);
```

```java
public class RandomCondition implements Condition, UrlReadingCondition {
    // Condition implementation
    @Override
    public void init(Map<String, String> map) {
    }

    @Override
    public boolean shouldDisplay(Map<String, Object> map) {
        // ...
    }

    // UrlReadingCondition implementation
    @Override
    public void addToUrl(UrlBuilder urlBuilder) {
        // ...
    }

    /**
     * Needs to be the same result as {@link #shouldDisplay(Map)}
     */
    @Override
    public boolean shouldDisplay(QueryParams queryParams) {
        // ...
    }
}
```

### 6. Define a condition with parameters

To add parameters to the conditions you can use multiple `@condition` annotations. These parameters will be passed in to the condition's `init()` method as a map of string key/value pairs.

The first part of `@condition` annotation is a property path, and the second part is the property value.

```ts
import { LinkExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @condition class com.atlassian.cse.demo.RandomCondition
 * @condition params.0.attributes.name permission
 * @condition params.0.value admin
 * @condition params.1.attributes.name location
 * @condition params.1.value menu
 */
export default LinkExtension.factory(/*...*/);
```

These `@condition` annotations will result in creating a condition map object that is matching the [shape of `conditionMap` option from `atlassian-webresource-webpack-plugin`](https://www.npmjs.com/package/atlassian-webresource-webpack-plugin#conditionmap-optional):

```json
{
    "class": "com.atlassian.cse.demo.RandomCondition",
    "params": [
        {
            "attributes": {
                "name": "permission"
            },
            "value": "admin"
        },
        {
            "attributes": {
                "name": "location"
            },
            "value": "menu"
        }
    ]
}
```

### 7. Defining multiple conditions

You can make use of AND / OR keywords to combine multiple conditions for your extension as follows:

```ts
import { LinkExtension } from '@atlassian/clientside-extensions';

/**
 * @clientside-extension
 * @extension-point example.extension.point
 * @condition type AND
 * @condition conditions.0.type OR
 * @condition conditions.0.conditions.0.class com.atlassian.cse.demo.RandomCondition
 * @condition conditions.0.conditions.0.invert true
 * @condition conditions.0.conditions.0.params.0.attributes.name permission
 * @condition conditions.0.conditions.0.params.0.value admin
 * @condition conditions.0.conditions.1.class com.atlassian.cse.demo.SuperCondition
 * @condition conditions.0.conditions.1.invert true
 * @condition conditions.0.conditions.1.params.0.attributes.name permission
 * @condition conditions.0.conditions.1.params.0.value project
 * @condition conditions.1.class com.atlassian.cse.demo.PerfecCondition
 * @condition conditions.1.params.0.attributes.name permission
 * @condition conditions.1.params.0.value admin
 */
export default LinkExtension.factory(/*...*/);
```

These `@condition` annotations will result in creating a condition map object that is matching the [shape of `conditionMap` option from `atlassian-webresource-webpack-plugin`](https://www.npmjs.com/package/atlassian-webresource-webpack-plugin#conditionmap-optional):

```json
{
    "type": "AND",
    "conditions": [
        {
            "type": "OR",
            "conditions": [
                {
                    "class": "com.atlassian.cse.demo.RandomCondition",
                    "invert": true,
                    "params": [
                        {
                            "attributes": {
                                "name": "permission"
                            },
                            "value": "admin"
                        }
                    ]
                },
                {
                    "class": "com.atlassian.cse.demo.SuperCondition",
                    "invert": true,
                    "params": [
                        {
                            "attributes": {
                                "name": "permission"
                            },
                            "value": "project"
                        }
                    ]
                }
            ]
        },
        {
            "class": "com.atlassian.cse.demo.PerfectCondition",
            "params": [
                {
                    "attributes": {
                        "name": "permission"
                    },
                    "value": "admin"
                }
            ]
        }
    ]
}
```
