---
title: "Implement new widget"
manual: "Dashboard"
version: "14.3"
permalink: "https://docs.typo3.org/permalink/typo3/cms-dashboard:implement-new-widget@14.3"
source: "Developer/WidgetImplementation.rst"
rendered: "2026-10-13T09:25:04+00:00"
---

# Implement new widget {#implement-new-widget}

<!-- TODO: no Markdown rendering for "versionadded" -->

Configurable Dashboard Widgets
have been introduced with TYPO3 14.0.See also

> [!NOTE]
> **See also**
>
> For information regarding registration of widgets, see: [Register new Widget](https://docs.typo3.org/permalink/typo3/cms-dashboard:register-new-widget@14.3).
> This section describes the implementation of new widgets for developers.

Each extension can provide multiple Widgets.
ext:dashboard already ships with some widget implementations.

Each widget has to be implemented as a PHP class.
The PHP class defines the concrete implementation and features of a widget,
while registration adds necessary options for a concrete instance of a widget.

For example a TYPO3.org RSS Widget would consist of an `RssWidget` PHP class.
This class would provide the implementation to fetch rss news and display them.
The concrete registration will provide the URL to RSS feed.

## PHP class {#widget-php-class}

Each Widget has to be a PHP class.
This class has to implement the `WidgetInterface` and could look like this:

```php
class RssWidget implements WidgetInterface, RequestAwareWidgetInterface
{
    private ServerRequestInterface $request;

    public function __construct(
        private readonly WidgetConfigurationInterface $configuration,
        private readonly Cache $cache,
        private readonly BackendViewFactory $backendViewFactory,
        private readonly ?ButtonProviderInterface $buttonProvider = null,
        private readonly array $options = []
    ) {
    }

    public function setRequest(ServerRequestInterface $request): void
    {
        $this->request = $request;
    }

    public function renderWidgetContent(): string
    {
        $view = $this->backendViewFactory->create($this->request);
        $view->assignMultiple([
            'items' => $this->getRssItems(),
            'options' => $this->options,
            'button' => $this->getButton(),
            'configuration' => $this->configuration,
        ]);
        return $view->render('Widget/RssWidget');
    }

    protected function getRssItems(): array
    {
        $items = [];
        // Logic to populate $items array
        return $items;
    }

    public function getOptions(): array
    {
        return $this->options;
    }
}
```

The class should always provide documentation how to use in `Services.yaml`.
The above class is documented at [RSS Widget](https://docs.typo3.org/permalink/typo3/cms-dashboard:rss-widget@14.3).
The documentation should provide all possible options and an concrete example.
It should make it possible for integrators to register new widgets using the implementation.

The difference between `$options` and `$configuration` in above example is the following:
`$options` are the options for this implementation which can be provided through `Services.yaml`.
`$configuration` is an instance of `WidgetConfigurationInterface`
holding all internal configuration, like icon identifier.

## Using Fluid {#implement-new-widget-fluid}

Most widgets will need a template.
Therefore each widget can define `BackendViewFactory` as requirement for DI in
constructor, like done in RSS example.

## Providing custom JS {#implement-new-widget-custom-js}

There are two ways to add JavaScript for an widget:

-   **JavaScript module**

    Implement `\TYPO3\CMS\Dashboard\Widgets\JavaScriptInterface`:

    ```php
    class ExampleChartWidget implements JavaScriptInterface
    {
        // ...
        public function getJavaScriptModuleInstructions(): array
        {
            return [
                JavaScriptModuleInstruction::create(
                    '@myvendor/my-extension/module-name.js'
                )->invoke('initialize'),
                JavaScriptModuleInstruction::create(
                    '@myvendor/my-extension/module-name2.js'
                )->invoke('initialize'),
            ];
        }
    }
    ```

    > [!NOTE]
    > **See also**
    >
    > [ES6 in the TYPO3 backend](https://docs.typo3.org/m/typo3/reference-coreapi/14.3/en-us/ApiOverview/Backend/JavaScript/ES6/Index.html#backend-javascript-es6) for more info about JavaScript in TYPO3 Backend.

-   **Plain JS files**

    Implement `AdditionalJavaScriptInterface`:

    ```php
    class RssWidget implements WidgetInterface, AdditionalJavaScriptInterface
    {
        public function getJsFiles(): array
        {
            return [
                'EXT:my_extension/Resources/Public/JavaScript/file.js',
                'EXT:my_extension/Resources/Public/JavaScript/file2.js',
            ];
        }
    }
    ```

-   **JavaScript**

    Implement `\TYPO3\CMS\Dashboard\Widgets\JavaScriptInterface`:

    ```php
    class ExampleChartWidget implements JavaScriptInterface
    {
        // ...
        public function getJavaScriptModuleInstructions(): array
        {
            return [
                JavaScriptModuleInstruction::create(
                    '@typo3/dashboard/chart-initializer.js'
                )->invoke('initialize'),
            ];
        }
    }
    ```

All ways can be combined.

## Providing custom CSS {#custom-css}

It is possible to add custom Css to style widgets.

Implement `AdditionalCssInterface`:

```php
class RssWidget implements WidgetInterface, AdditionalCssInterface
{
      public function getCssFiles(): array
      {
         return [
             'EXT:my_extension/Resources/Public/Css/widgets.css',
             'EXT:my_extension/Resources/Public/Css/list-widget.css',
         ];
      }
}
```
