---
title: "Template Overrides"
manual: "RTE CKEditor Image"
version: "main"
permalink: "https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:examples-template-overrides@main"
source: "Examples/Template-Overrides.rst"
rendered: "2026-10-01T01:27:51+00:00"
---

# Template Overrides {#examples-template-overrides}

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

The new Fluid-based rendering architecture allows complete customization
of image output via template overrides.

Override the default Fluid templates to customize image rendering output
for your site's design requirements.

**Table of contents**

-   [Overview](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:overview@main)
-   [Setting up overrides](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:setting-up-overrides@main)
-   [Available DTO properties](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:available-dto-properties@main)
-   [Example overrides](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:example-overrides@main)
-   [Best practices](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:best-practices@main)
-   [Debugging templates](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:debugging-templates@main)
-   [Related documentation](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:related-documentation@main)

## Overview {#overview}

The extension provides six Fluid templates for different rendering contexts:

**Template directory structure**

```text
Resources/Private/
├── Templates/Image/
│   ├── Standalone.html       # Basic image without wrapper
│   ├── WithCaption.html      # Image with <figure>/<figcaption>
│   ├── Link.html             # Image wrapped in <a> tag
│   ├── LinkWithCaption.html  # Linked image with caption
│   ├── Popup.html            # Image with lightbox/popup link
│   └── PopupWithCaption.html # Popup image with caption
└── Partials/Image/
    ├── Tag.html              # <img> element partial
    ├── TagInFigure.html      # <img> without class (for figures)
    ├── Link.html             # <a> wrapper partial
    └── Figure.html           # <figure> wrapper partial
```

> [!NOTE]
> Partials ship in the standard TYPO3 location
> `Resources/Private/Partials/Image/` (see
> [#547](https://github.com/netresearch/t3x-rte_ckeditor_image/issues/547)).
> Templates live in `Resources/Private/Templates/Image/` and layouts in
> `Resources/Private/Templates/Layouts/`. When overriding, point your
> `partialRootPaths` at your site package's `Resources/Private/Partials/`.

> [!WARNING]
> In `EXT:` paths, use the **extension key** `rte_ckeditor_image`
> (underscores) — *not* the Composer package name `rte-ckeditor-image`
> (hyphens). TYPO3 resolves `EXT:` references by extension key only, so a
> hyphenated path silently resolves to nothing and the override is ignored.

### Template selection {#template-selection}

The `ImageRenderingService` automatically selects the appropriate template:

| Condition | Template |
| --- | --- |
| No link, no caption | `Standalone.html` |
| No link, has caption | `WithCaption.html` |
| Has link, no popup, no caption | `Link.html` |
| Has link, no popup, has caption | `LinkWithCaption.html` |
| Has popup, no caption | `Popup.html` |
| Has popup, has caption | `PopupWithCaption.html` |

#### Inline vs block rendering {#inline-vs-block-rendering}

Images are rendered differently depending on whether they appear as **block**
elements (`<figure>`) or **inline** elements (`<img>` within text flow).
Understanding this distinction is important when overriding templates:

-   ****Block images** (`<figure>`):**

    Processed by `renderFigure()`. The template handles everything including
    the link wrapper. Uses `Link.html`, `LinkWithCaption.html`,
    `Popup.html`, or `PopupWithCaption.html`.

-   ****Inline images** (`<img>` in text flow):**

    Processed by `renderImageAttributes()` for the `<img>` element. The
    template only renders the `<img>` tag — always `Standalone.html`.
    The surrounding `<a>` wrapper is rebuilt by the default `tags.a`
    typolink in `parseFunc_RTE` (resolves `t3://` URLs, applies
    `rel="noreferrer"`, etc.); it is not rendered through a Fluid template.

-   ****Popup images**:**

    Both inline and block use `Popup.html` or `PopupWithCaption.html`
    because popup attributes (lightbox data, click handler) require special
    template handling.

| Context | Link | Caption | Handler | Template |
| --- | --- | --- | --- | --- |
| Block | No | No | `renderFigure()` | `Standalone.html` |
| Block | No | Yes | `renderFigure()` | `WithCaption.html` |
| Block | Yes | No | `renderFigure()` | `Link.html` |
| Block | Yes | Yes | `renderFigure()` | `LinkWithCaption.html` |
| Block | Popup | No | `renderFigure()` | `Popup.html` |
| Block | Popup | Yes | `renderFigure()` | `PopupWithCaption.html` |
| Inline | No | — | `renderImageAttributes()` | `Standalone.html` |
| Inline | Yes | — | `renderImageAttributes()` (link rebuilt by default `tags.a` typolink) | `Standalone.html` |
| Inline | Popup | — | `renderImageAttributes()` | `Popup.html` |

## Setting up overrides {#setting-up-overrides}

### Step 1: Create template directory {#step-1-create-template-directory}

In your site package, create the override directory:

**Create template override directory**

```bash
mkdir -p packages/my_sitepackage/Resources/Private/Templates/Image/
```

### Step 2: Configure TypoScript {#step-2-configure-typoscript}

Add the template path to your TypoScript setup. The `settings.` block
must live **inside** `preUserFunc.` — that is the only sub-array TYPO3
forwards to the rendering callable (see
`ContentObjectRenderer::stdWrap_preUserFunc()`, which passes only
`$conf['preUserFunc.']` to the user function). Placing
`settings.templateRootPaths` as a sibling of `preUserFunc` has no
effect — the configuration never reaches
`ImageRenderingService::buildTemplatePaths()`.

**EXT:my_sitepackage/Configuration/TypoScript/setup.typoscript**

```typoscript
lib.parseFunc_RTE.tags.img.preUserFunc {
    # Add your templates with higher priority (higher number = higher priority)
    settings {
        templateRootPaths {
            10 = EXT:my_sitepackage/Resources/Private/Templates/
        }
        partialRootPaths {
            10 = EXT:my_sitepackage/Resources/Private/Partials/
        }
        layoutRootPaths {
            10 = EXT:my_sitepackage/Resources/Private/Layouts/
        }
    }
}

# Captioned images render as <figure> blocks and are processed via
# externalBlocks.figure.stdWrap.preUserFunc (renderFigure). The same
# settings. block has to be duplicated here for figure rendering.
lib.parseFunc_RTE.externalBlocks.figure.stdWrap.preUserFunc {
    settings {
        templateRootPaths {
            10 = EXT:my_sitepackage/Resources/Private/Templates/
        }
        partialRootPaths {
            10 = EXT:my_sitepackage/Resources/Private/Partials/
        }
        layoutRootPaths {
            10 = EXT:my_sitepackage/Resources/Private/Layouts/
        }
    }
}
```

> [!NOTE]
> Figures are processed via `externalBlocks`, not `tags.figure` —
> placing the configuration under `tags.figure` has no effect. Inline
> images wrapped in `<a>` are rendered by `tags.img` (recursively,
> inside the link wrapper), so they already pick up the configuration
> defined under `tags.img.preUserFunc`.

### Step 3: Create override templates {#step-3-create-override-templates}

Copy and modify only the templates you need to customize.

## Available DTO properties {#available-dto-properties}

All templates receive the `image` variable containing an `ImageRenderingDto`:

**Available template variables**

```html
<!-- Core properties -->
{image.src}                    <!-- Processed image URL -->
{image.width}                  <!-- Display width in pixels -->
{image.height}                 <!-- Display height in pixels -->
{image.alt}                    <!-- Alternative text -->
{image.title}                  <!-- Title attribute -->
{image.caption}                <!-- Caption text (XSS-sanitized) -->
{image.isMagicImage}           <!-- Whether TYPO3 processing applied -->

<!-- HTML attributes -->
{image.htmlAttributes.class}   <!-- CSS classes -->
{image.htmlAttributes.style}   <!-- Inline styles -->
{image.htmlAttributes.loading} <!-- lazy/eager -->

<!-- Link properties (when linked) -->
{image.link.url}               <!-- Link URL -->
{image.link.target}            <!-- Link target (_blank, etc.) -->
{image.link.class}             <!-- Link CSS classes -->
{image.link.isPopup}           <!-- Whether popup/lightbox -->
```

See [ImageRenderingDto](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:api-imagerenderingdto@main) for complete property documentation.

## Example overrides {#example-overrides}

### Bootstrap 5 responsive image {#bootstrap-5-responsive-image}

Override `Standalone.html` for Bootstrap 5 responsive images:

**EXT:my_sitepackage/Resources/Private/Templates/Image/Standalone.html**

```html
<img src="{image.src}"
     alt="{image.alt}"
     width="{image.width}"
     height="{image.height}"
     class="img-fluid {image.htmlAttributes.class}"
     {f:if(condition: image.title, then: 'title="{image.title}"')}
     {f:if(condition: image.htmlAttributes.style, then: 'style="{image.htmlAttributes.style}"')}
     loading="lazy"
     decoding="async" />
```

### Figure with custom styling {#figure-with-custom-styling}

Override `WithCaption.html` for custom figure styling:

**EXT:my_sitepackage/Resources/Private/Templates/Image/WithCaption.html**

```html
<figure class="content-image{f:if(condition: image.htmlAttributes.class, then: ' {image.htmlAttributes.class}')}">
    <img src="{image.src}"
         alt="{image.alt}"
         width="{image.width}"
         height="{image.height}"
         class="content-image__img"
         {f:if(condition: image.title, then: 'title="{image.title}"')}
         loading="lazy"
         decoding="async" />
    <figcaption class="content-image__caption">
        {image.caption}
    </figcaption>
</figure>
```

### PhotoSwipe lightbox integration {#photoswipe-lightbox-integration}

Override `Popup.html` for PhotoSwipe v5 integration:

**EXT:my_sitepackage/Resources/Private/Templates/Image/Popup.html**

```html
<a href="{image.link.url}"
   class="pswp-gallery__item {image.link.class}"
   data-pswp-width="{image.width}"
   data-pswp-height="{image.height}"
   {f:if(condition: image.link.target, then: 'target="{image.link.target}"')}>
    <img src="{image.src}"
         alt="{image.alt}"
         width="{image.width}"
         height="{image.height}"
         {f:if(condition: image.title, then: 'title="{image.title}"')}
         {f:if(condition: image.htmlAttributes.class, then: 'class="{image.htmlAttributes.class}"')}
         loading="lazy"
         decoding="async" />
</a>
```

### Lazy loading with placeholder {#lazy-loading-with-placeholder}

Override `Standalone.html` for progressive image loading:

**Lazy loading with SVG placeholder**

```html
<img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 {image.width} {image.height}'%3E%3C/svg%3E"
     data-src="{image.src}"
     alt="{image.alt}"
     width="{image.width}"
     height="{image.height}"
     class="lazyload {image.htmlAttributes.class}"
     {f:if(condition: image.title, then: 'title="{image.title}"')}
     {f:if(condition: image.htmlAttributes.style, then: 'style="{image.htmlAttributes.style}"')}
     decoding="async" />
```

## Best practices {#best-practices}

1.  **Only override what you need**: Copy only templates requiring changes.
1.  **Preserve accessibility**: Always include `alt` attribute and maintain semantic HTML.
1.  **Keep security intact**: The DTO properties are pre-sanitized. Do not apply additional encoding
    that could double-escape content.
1.  **Test all contexts**: Verify overrides work with captions, links, and popups.
1.  **Use native lazy loading**: Prefer `loading="lazy"` over JavaScript solutions.
1.  **CSS classes move to figure**: When images have captions, CSS classes defined on the
    `<img>` element are applied to the `<figure>` wrapper instead. This ensures valid HTML5
    semantics. If you need classes specifically on the `<img>` within a figure, create a
    custom `WithCaption.html` template override.
1.  **Decoding attribute**: The default templates include `decoding="async"` on all images
    to improve rendering performance by allowing the browser to decode images off the main thread.
    This is a modern best practice that does not affect visual output.
1.  **Whitespace is stripped**: The rendering service removes whitespace between HTML tags
    to prevent `parseFunc_RTE` from creating `<p>&nbsp;</p>` artifacts. Templates can use
    readable multi-line formatting; it will be normalized. However, deliberate spacing between
    inline elements will be removed.

## Debugging templates {#debugging-templates}

Enable Fluid debugging to inspect available variables:

**Debug all template variables**

```html
<f:debug>{_all}</f:debug>
```

Or in TypoScript:

**Enable debug mode via TypoScript**

```typoscript
lib.parseFunc_RTE.settings.debug = 1
```

## Related documentation {#related-documentation}

-   [ImageRenderingService](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:api-imagerenderingservice@main) \- Template selection logic.
-   [ImageRenderingDto](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:api-imagerenderingdto@main) \- Available DTO properties.
-   [Image styles](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:examples-image-styles@main) \- CSS class configuration.
