---
title: "Assets (CSS, JavaScript, Media)"
manual: "TYPO3 Explained"
version: "13.4"
permalink: "https://docs.typo3.org/permalink/t3coreapi:assets@13.4"
source: "ApiOverview/Assets/Index.rst"
rendered: "2026-10-01T12:09:27+00:00"
---

# Assets (CSS, JavaScript, Media) {#assets}

****Table of Contents****

-   [Asset collector](https://docs.typo3.org/permalink/t3coreapi:asset-collector-1@13.4)
-   [Using the page renderer to add assets](https://docs.typo3.org/permalink/t3coreapi:using-the-page-renderer-to-add-assets@13.4)

The TYPO3 component responsible for rendering the HTML and adding assets to a
TYPO3 frontend or backend page is called `\TYPO3\CMS\Core\Page\PageRenderer`.

The `PageRenderer` collects all assets to be rendered, takes care of
options such as concatenation or compression and finally generates the necessary
tags.

There are multiple ways to add assets to the `PageRenderer` in TYPO3.
For configuration options via TypoScript (usually used for the main theme files),
see the [TypoScript Reference](https://docs.typo3.org/m/typo3/reference-typoscript/13.4/en-us/TopLevelObjects/Page/Index.html#setup-page-includecss-array). In
extensions, both directly using the `PageRenderer` as well as using the
more convenient `AssetCollector` is possible.

## Asset collector {#asset-collector}

With the `\TYPO3\CMS\Core\Page\AssetCollector` class, CSS and JavaScript
code (inline or external) can be added multiple times, but rendered only once in
the output. The class may be used directly in PHP code or the assets can be
added via the `<f:asset.css>` and `<f:asset.script>` ViewHelpers.

The `priority` flag (default: `false`) controls where the asset is
inserted:

-   JavaScript will be output inside `<head>` if `$priority == true`,
    or at the bottom of the `<body>` tag if `$priority == false`.
-   CSS will always be output inside `<head>`, yet grouped by
    `$priority`.

The asset collector helps to work with content elements as components,
effectively reducing the CSS to be loaded. It takes advantage of HTTP/2, which
removes the necessity to concatenate all files in one file.

The asset collector class is implemented as a singleton
(`\TYPO3\CMS\Core\SingletonInterface`). It replaces various other existing
options in TypoScript and [methods in PHP](https://docs.typo3.org/permalink/t3coreapi:assets-other-methods@13.4) for
inserting JavaScript and CSS code.

The asset collector also collects information about images on a page,
which can be used in cached and non-cached components.

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

Option external to skip URL processing in AssetRenderer has been added.

The `AssetCollector` option `external` can be used for
asset files using `$assetCollector->addStyleSheet()`
or `$assetCollector->addJavaScript()`. If set all processing of the asset
URI (like the addition of the cache busting parameter) is skipped and the input
path will be used as-is in the resulting HTML tag.

### The Asset collector API {#asset-collector-api}

-   **class AssetCollector**

    -   *Fully qualified name:* `\TYPO3\CMS\Core\Page\AssetCollector`

    The Asset Collector is responsible for keeping track of
    1\) everything within \<script> tags: javascript files and inline javascript code and
    2\) inline CSS and CSS files

    The goal of the asset collector is to
    1\) utilize a single "runtime-based" store for adding assets of certain kinds that are added to the output
    2\) allow assets from non-cacheable plugins and cacheable content to be dealt with in the Frontend
    3\) reduce the "power" and flexibility (I'd say it's a burden) of the "god class" PageRenderer
    4\) reduce the burden of storing everything in PageRenderer.

    As a side effect, this allows a single CSS snippet or CSS file to be added per
    content block, but the CSS is only added once to the output.

    Note on the implementation.
    We use a Singleton to make use of the AssetCollector throughout the Frontend process (similar to PageRenderer).
    Although this is not optimal, I don't see any other way to do so in the current code.

    -   **addJavaScript(string $identifier, string $source, array $attributes = \[\], array $options = \[\])**

        -   *param $identifier:* the identifier
        -   *param $source:* URI to JavaScript file (allows EXT: syntax)
        -   *param $attributes:* additional HTML \<script> tag attributes, default: \[\]
        -   *param $options:* \['priority' => true\] means rendering before other tags, default: \[\]

        *Returns:* `self`

    -   **addJavaScriptModule(string $identifier)**

        -   *param $identifier:* Bare module identifier like @my/package/Filename.js

        *Returns:* `self`

    -   **addInlineJavaScript(string $identifier, string $source, array $attributes = \[\], array $options = \[\])**

        -   *param $identifier:* the identifier
        -   *param $source:* JavaScript code
        -   *param $attributes:* additional HTML \<script> tag attributes, default: \[\]
        -   *param $options:* \['priority' => true\] means rendering before other tags, default: \[\]

        *Returns:* `self`

    -   **addStyleSheet(string $identifier, string $source, array $attributes = \[\], array $options = \[\])**

        -   *param $identifier:* the identifier
        -   *param $source:* URI to stylesheet file (allows EXT: syntax)
        -   *param $attributes:* additional HTML \<link> tag attributes, default: \[\]
        -   *param $options:* \['priority' => true\] means rendering before other tags, default: \[\]

        *Returns:* `self`

    -   **addInlineStyleSheet(string $identifier, string $source, array $attributes = \[\], array $options = \[\])**

        -   *param $identifier:* the identifier
        -   *param $source:* stylesheet code
        -   *param $attributes:* additional HTML \<link> tag attributes, default: \[\]
        -   *param $options:* \['priority' => true\] means rendering before other tags, default: \[\]

        *Returns:* `self`

    -   **addMedia(string $fileName, array $additionalInformation)**

        -   *param $fileName:* the fileName
        -   *param $additionalInformation:* One dimensional hash map (array with non-numerical keys) with scalar values

        *Returns:* `self`

    -   **removeJavaScript(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `self`

    -   **removeInlineJavaScript(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `self`

    -   **removeStyleSheet(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `self`

    -   **removeInlineStyleSheet(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `self`

    -   **removeMedia(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `self`

    -   **getMedia()**

        *Returns:* `array`

    -   **getJavaScripts(?bool $priority = NULL)**

        -   *param $priority:* the priority, default: NULL

        *Returns:* `array`

    -   **getInlineJavaScripts(?bool $priority = NULL)**

        -   *param $priority:* the priority, default: NULL

        *Returns:* `array`

    -   **getJavaScriptModules()**

        *Returns:* `array`

    -   **getStyleSheets(?bool $priority = NULL)**

        -   *param $priority:* the priority, default: NULL

        *Returns:* `array`

    -   **getInlineStyleSheets(?bool $priority = NULL)**

        -   *param $priority:* the priority, default: NULL

        *Returns:* `array`

    -   **hasJavaScript(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `bool`

    -   **hasInlineJavaScript(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `bool`

    -   **hasStyleSheet(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `bool`

    -   **hasInlineStyleSheet(string $identifier)**

        -   *param $identifier:* the identifier

        *Returns:* `bool`

    -   **hasMedia(string $fileName)**

        -   *param $fileName:* the fileName

        *Returns:* `bool`

> [!NOTE]
> If the same asset is registered multiple times using different attributes or
> options, both sets are merged. If the same attributes or options are given
> with different values, the most recently registered ones overwrite the
> existing ones. The `has` methods can be used to check if an asset
> exists before generating it again, hence avoiding redundancy.

### f:assets.\* ViewHelpers {#assets-viewhelper}

There are two ViewHelpers which use the `AssetCollector` API - [f:asset.css](https://docs.typo3.org/other/typo3/view-helper-reference/13.4/en-us/Global/Asset/Css.html#typo3-fluid-asset-css) and the
[f:asset.script](https://docs.typo3.org/other/typo3/view-helper-reference/13.4/en-us/Global/Asset/Script.html#typo3-fluid-asset-script).

### Rendering order of page assets {#assets-rendering-order}

Currently, CSS and JavaScript registered with the asset collector will be
rendered after their page renderer counterparts. The order is:

-   `<head>`
-   `page.includeJSLibs.forceOnTop`
-   `page.includeJSLibs`
-   `page.includeJS.forceOnTop`
-   `page.includeJS`
-   `AssetCollector::addJavaScript()` with 'priority'
-   `page.jsInline`
-   `AssetCollector::addInlineJavaScript()` with 'priority'
-   `</head>`
-   `page.includeJSFooterlibs.forceOnTop`
-   `page.includeJSFooterlibs`
-   `page.includeJSFooter.forceOnTop`
-   `page.includeJSFooter`
-   `AssetCollector::addJavaScript()`
-   `page.jsFooterInline`
-   `AssetCollector::addInlineJavaScript()`

> [!NOTE]
> JavaScript registered with the asset collector is not affected by
> [config.moveJsFromHeaderToFooter](https://docs.typo3.org/m/typo3/reference-typoscript/13.4/en-us/TopLevelObjects/Config.html#setup-config-movejsfromheadertofooter).

### Examples {#assets-examples}

The `AssetCollector` can be injected in the constructor of a class via
[dependency injection](https://docs.typo3.org/permalink/t3coreapi:dependencyinjection@13.4) and then used in methods:

**EXT:my_extension/Classes/MyClass.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\MyClass;

use TYPO3\CMS\Core\Page\AssetCollector;

final class MyClass
{
  public function __construct(
    private readonly AssetCollector $assetCollector,
  ) {}

  public function doSomething()
  {
    // $this->assetCollector can now be used
    // see examples below
  }
}

```

Add a JavaScript file to the collector with script attribute
`data-foo="bar"`:

**EXT:my_extension/Classes/MyClass.php**

```php
$this->assetCollector->addJavaScript(
    'my_ext_foo',
    'EXT:my_extension/Resources/Public/JavaScript/foo.js',
    ['data-foo' => 'bar']
);
```

Add a JavaScript file to the collector with script attribute
`data-foo="bar"` and a priority which means rendering before other script
tags:

**EXT:my_extension/Classes/MyClass.php**

```php
$this->assetCollector->addJavaScript(
    'my_ext_foo',
    'EXT:my_extension/Resources/Public/JavaScript/foo.js',
    ['data-foo' => 'bar'],
    ['priority' => true]
);
```

Add a JavaScript file to the collector with `type="module"` (by default,
no `type=` is output for JavaScript):

**EXT:my_extension/Classes/MyClass.php**

```php
$this->assetCollector->addJavaScript(
    'my_ext_foo',
    'EXT:my_extension/Resources/Public/JavaScript/foo.js',
    ['type' => 'module']
);
```

Check if a JavaScript file with the given identifier exists:

**EXT:my_extension/Classes/MyClass.php**

```php
if ($this->assetCollector->hasJavaScript($identifier)) {
    // result: true - JavaScript with identifier $identifier exists
} else {
    // result: false - JavaScript with identifier $identifier does not exist
}
```

The following code skips the cache busting parameter `?1726090820` for the supplied CSS file:

**EXT:my_extension/Classes/MyClass.php**

```php
$assetCollector->addStyleSheet(
    'myCssFile',
    PathUtility::getAbsoluteWebPath(GeneralUtility::getFileAbsFileName('EXT:my_extension/Resources/Public/MyFile.css')),
    [],
    ['external' => true]
);
```

Resulting in the following HTML output:

```html
<link rel="stylesheet" href="/_assets/<hash>/myFile.css" />
```

### Events that allow additional adjusting of assets {#assets-events}

There are two events available that allow additional adjusting of assets:

-   [BeforeJavaScriptsRenderingEvent](https://docs.typo3.org/permalink/t3coreapi:beforejavascriptsrenderingevent@13.4)
-   [BeforeStylesheetsRenderingEvent](https://docs.typo3.org/permalink/t3coreapi:beforestylesheetsrenderingevent@13.4)

## Using the page renderer to add assets {#assets-page-renderer}

An instance of the `\TYPO3\CMS\Core\Page\PageRenderer`
class can be injected via [dependency injection](https://docs.typo3.org/permalink/t3coreapi:dependencyinjection@13.4):

**EXT:my_extension/Classes/MyClass.php**

```php
<?php

declare(strict_types=1);

namespace MyVendor\MyExtension\MyClass;

use TYPO3\CMS\Core\Page\PageRenderer;

final class MyClass
{
  public function __construct(
    private readonly PageRenderer $pageRenderer,
  ) {}

  public function doSomething()
  {
    // $this->pageRenderer can now be used
    // see examples below
  }
}

```

The following methods can then be used:

-   `$this->pageRenderer->addHeaderData($javaScriptCode)`
-   `$this->pageRenderer->addCssFile($file)`
-   `$this->pageRenderer->addCssInlineBlock($name, $cssCode)`
-   `$this->pageRenderer->addCssLibrary($file)`
-   `$this->pageRenderer->addJsFile($file)`
-   `$this->pageRenderer->addJsFooterFile($file)`
-   `$this->pageRenderer->addJsFooterLibrary($name, $file)`
-   `$this->pageRenderer->addJsFooterInlineCode($name, $javaScriptCode)`
-   `$this->pageRenderer->addJsInlineCode($name, $javaScriptCode)`
-   `$this->pageRenderer->addJsLibrary($name, $file)`

### Using the TypoScriptFrontendController {#assets-typoscriptfrontendcontroller}

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

The property additionalHeaderData has been marked as internal
and should not be used. Use AssetCollector->addJavaScript() instead
(like described in the examples above).

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

The class \TYPO3\CMS\Frontend\Controller\TypoScriptFrontendController
and its global instance $GLOBALS['TSFE'] have been marked as
deprecated. The class will be removed with TYPO3 v14.

```php
$GLOBALS['TSFE']->additionalHeaderData[$name] = $javaScriptCode;
```
