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

# Advanced Features {#examples-advanced-features}

Examples for implementing lightbox functionality and lazy loading for performance optimization.

**Table of Contents**

-   [Lightbox Integration](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:lightbox-integration@main)
-   [Lazy Loading](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:lazy-loading@main)
-   [Related Documentation](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:related-documentation@main)

## Lightbox Integration {#lightbox-integration}

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

Default popup configuration is now provided automatically.
The basic "Enlarge on Click" feature works out-of-the-box without additional setup.
See Frontend Rendering for details.

### Popup Link Configuration {#popup-link-configuration}

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

The popup link CSS class is now configurable via TypoScript.

By default, popup links use the CSS class `popup-link`. You can customize this
to integrate with your lightbox library or styling framework.

#### Simple Configuration {#simple-configuration}

Set a custom class directly:

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

```typoscript
lib.contentElement.settings.media.popup {
    # Set custom CSS class for popup/lightbox links
    linkClass = lightbox
}
```

#### Advanced Configuration (ATagParams) {#advanced-configuration-atagparams}

For backward compatibility with existing TypoScript configurations, the extension
can also extract the CSS class from `linkParams.ATagParams`:

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

```typoscript
lib.contentElement.settings.media.popup {
    linkParams.ATagParams = class="fancybox gallery-item"
}
```

> [!IMPORTANT]
> Only the `class` attribute is extracted from `ATagParams`. Other attributes
> like `data-*`, `rel`, or `target` are **not** applied to the popup link.
> For full attribute control, use a custom Fluid template override or PHP hook.

> [!NOTE]
> `linkClass` takes precedence over the class extracted from `ATagParams`.
> Use `linkClass` for simple configuration (recommended).

### PhotoSwipe Lightbox {#photoswipe-lightbox}

**Objective**: Integrate PhotoSwipe lightbox library for advanced gallery features

> [!NOTE]
> For basic click-to-enlarge functionality, the extension provides default popup configuration.
> PhotoSwipe integration is optional for advanced features like galleries, thumbnails, and touch gestures.

#### Install PhotoSwipe {#install-photoswipe}

```bash
npm install photoswipe
```

#### TypoScript Setup {#typoscript-setup}

```typoscript
page {
    includeJSFooterlibs {
        photoswipe = EXT:my_site/Resources/Public/JavaScript/photoswipe.min.js
        photoswipe_init = EXT:my_site/Resources/Public/JavaScript/lightbox-init.js
    }

    includeCSS {
        photoswipe = EXT:my_site/Resources/Public/Css/photoswipe.css
    }
}

lib.parseFunc_RTE {
    tags.img = TEXT
    tags.img {
        current = 1
        preUserFunc = MyVendor\MySite\UserFunc\LightboxImageRenderer->render
    }
}
```

#### PHP Wrapper {#php-wrapper}

**EXT:my_site/Classes/UserFunc/LightboxImageRenderer.php**

```php
namespace MyVendor\MySite\UserFunc;

use TYPO3\CMS\Core\Resource\FileRepository;
use TYPO3\CMS\Core\Utility\GeneralUtility;
use TYPO3\CMS\Frontend\ContentObject\ContentObjectRenderer;

class LightboxImageRenderer
{
    public function render(
        string $content,
        array $conf,
        ContentObjectRenderer $cObj
    ): string {
        // Check if zoom enabled
        if (strpos($content, 'data-htmlarea-zoom') === false) {
            return $content;
        }

        // Extract file UID
        if (!preg_match('/data-htmlarea-file-uid="(\d+)"/', $content, $match)) {
            return $content;
        }

        $fileUid = (int)$match[1];
        $fileRepository = GeneralUtility::makeInstance(FileRepository::class);

        try {
            $file = $fileRepository->findByUid($fileUid);
        } catch (\Exception $e) {
            return $content;
        }

        // Remove data attributes for frontend
        $content = preg_replace('/\s*data-htmlarea-[^=]+="[^"]*"/', '', $content);

        // Wrap in lightbox link
        $lightboxLink = sprintf(
            '<a href="%s" data-pswp-width="%d" data-pswp-height="%d" target="_blank">%s</a>',
            $file->getPublicUrl(),
            $file->getProperty('width'),
            $file->getProperty('height'),
            $content
        );

        return $lightboxLink;
    }
}
```

#### JavaScript Initialization {#javascript-initialization}

**EXT:my_site/Resources/Public/JavaScript/lightbox-init.js**

```javascript
import PhotoSwipeLightbox from 'photoswipe/lightbox';
import 'photoswipe/style.css';

const lightbox = new PhotoSwipeLightbox({
    gallery: '.ce-bodytext',
    children: 'a[data-pswp-width]',
    pswpModule: () => import('photoswipe'),
});

lightbox.init();
```

**Result**: Click-to-enlarge images with lightbox ✅

## Lazy Loading {#lazy-loading}

### Native Lazy Loading {#native-lazy-loading}

**Objective**: Improve page load performance with native lazy loading

#### TypoScript Setup {#typoscript-setup-1}

```typoscript
lib.parseFunc_RTE {
    nonTypoTagStdWrap.HTMLparser.tags.img {
        fixAttrib {
            loading {
                set = lazy
            }
            # Remove internal attributes
            data-htmlarea-file-uid.unset = 1
            data-htmlarea-file-table.unset = 1
            # Keep zoom attributes for popup/lightbox rendering
            # data-htmlarea-zoom.unset = 1
        }
    }
}
```

#### Result HTML {#result-html}

```html
<img src="..." loading="lazy" alt="..." />
```

### Intersection Observer Fallback {#intersection-observer-fallback}

**For older browsers**:

#### TypoScript {#typoscript}

```typoscript
page.includeJSFooterlibs.lazyload = EXT:my_site/Resources/Public/JavaScript/lazyload.js

lib.parseFunc_RTE {
    nonTypoTagStdWrap.HTMLparser.tags.img {
        fixAttrib {
            class {
                list = lazyload
            }
            data-src {
                # Copy src to data-src
                stdWrap.field = src
            }
            src {
                # Set placeholder
                set = data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 3 2'%3E%3C/svg%3E
            }
        }
    }
}
```

#### JavaScript {#javascript}

**EXT:my_site/Resources/Public/JavaScript/lazyload.js**

```javascript
document.addEventListener('DOMContentLoaded', function() {
    const imageObserver = new IntersectionObserver((entries, observer) => {
        entries.forEach(entry => {
            if (entry.isIntersecting) {
                const img = entry.target;
                img.src = img.dataset.src;
                img.classList.remove('lazyload');
                imageObserver.unobserve(img);
            }
        });
    });

    document.querySelectorAll('img.lazyload').forEach(img => {
        imageObserver.observe(img);
    });
});
```

**Result**: Progressive image loading ✅

## Related Documentation {#related-documentation}

-   [Responsive Images](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:examples-responsive-images@main) \- Responsive image implementation
-   [Custom Extensions](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:examples-custom-extensions@main) \- Custom dialog and extensions
-   [Integration & Configuration](https://docs.typo3.org/permalink/netresearch/rte-ckeditor-image:integration@main) \- Configuration guide
