Look 

Extension key

look

Package name

flowd/typo3-look

Version

main

Language

en

Author

Flowd GmbH

License

This document is published under the Open Publication License.

Rendered

Thu, 17 Sep 2026 14:56:56 +0000


"Look" what you'll see on your website: this extension shows content elements in the TYPO3 page module exactly as they appear in the frontend, rendered with the real templates, CSS and images of your site, inside an isolated preview frame.


Table of Contents:

Introduction 

What does it do? 

The TYPO3 page module normally shows a content element as a plain summary: a headline, the first lines of text, maybe a thumbnail. Editors have to open the frontend to see what they actually built.

Look changes that. It renders every content element with the real frontend templates, stylesheets and images of your website and shows the result directly in the page module, scaled down to fit. What you see in the backend is what visitors get on the website.

The TYPO3 page module showing content elements rendered with the real frontend design

Content elements in the page module, rendered with the frontend design of the site.

Each preview lives in its own isolated frame. It looks like the frontend but cannot interact with the backend: no clicks, no scripts of the page content, no access to the editor's session. The frame adapts its height to the content automatically, so short and tall elements both look natural.

A text and media element with headline, text and an image in the page module

A text and media element as editors see it: the frontend layout with headline, copy and image.

Who is it for? 

  • Editors see the effect of every setting immediately: a different header layout, a coloured section, an image position. No more switching between backend and frontend. With the edit overlay enabled, a click on the preview opens the element for editing.
  • Integrators reuse the frontend templates they already have. A preview is one Fluid tag around the existing rendering, there is no second template to keep in sync.
  • Administrators get previews that are safe by default. Scripts and media of the website are switched off inside the preview until they are explicitly allowed, see Security.

How does it work? 

Look ships one Fluid view helper, <look:backend.contentPreview>. You wrap it around the frontend markup of a content element, typically in the backend preview template of a Content Block. The view helper

  1. renders the markup you pass it,
  2. puts it into a complete HTML document together with the stylesheets and scripts of your site,
  3. and shows that document in a sandboxed <iframe> in the page module.

The frame reports its content height to the backend, so the page module always shows the whole element (or a fixed height with a fade-out, if you prefer). Everything else, from the design to the icons, comes from your own frontend build.

Compatibility 

Look version

TYPO3 version

PHP version

main

13.4 LTS, 14.3+

8.2 or later

Installation 

Install with Composer 

Look is installed like any other TYPO3 extension in a Composer based project:

composer require flowd/typo3-look
Copied!

Afterwards set up the extension so that TYPO3 picks up its configuration:

vendor/bin/typo3 extension:setup
Copied!

That is all for the extension itself. The previews appear as soon as a content element uses the view helper, see Usage.

If your frontend uses web fonts 

Look needs no web server configuration. One case is the exception: the preview frame runs with an opaque origin, and browsers fetch web fonts and JavaScript modules from such a frame as cross-origin requests. They only load if the server answers with Access-Control-Allow-Origin: * for the path they come from.

This affects web fonts of your frontend build, and the scripts of your build when you enable allowSiteScripts. Without the header the previews still work, they just use fallback fonts. Images, stylesheets and videos are not affected.

nginx, for the path your frontend build lives in
location ~* \.(woff2?|ttf|otf|mjs|js)$ {
    add_header Access-Control-Allow-Origin "*";
}
Copied!

The header is safe for public static files, it grants read access to bytes that are served publicly anyway and browsers never combine * with credentials. Do not add it to dynamic or authenticated paths.

Check the installation 

Open a page in the page module that contains a content element with a Look preview. You should see the element in the frontend design, scaled down. If you see the plain TYPO3 preview instead, the content element type does not use the view helper yet. If the frame stays empty or shows a red callout, see Known problems and how to solve.

Usage 

Look provides a single Fluid view helper. Wrap it around the frontend markup of a content element and the page module shows that markup as a real preview.

Previews for Content Blocks 

Content Blocks render the file templates/backend-preview.html of a content block in the page module. Reuse the frontend rendering there and wrap it in the view helper:

EXT:my_site/ContentBlocks/ContentElements/textmedia/templates/backend-preview.html
<html data-namespace-typo3-fluid="true"
      xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
      xmlns:look="http://typo3.org/ns/Flowd/Typo3Look/ViewHelper"
      xmlns:my="http://typo3.org/ns/Vendor/MySite/Components/ComponentCollection">
<f:layout name="Preview" />
<f:section name="Content">
    <look:backend.contentPreview
        bodyClass="application"
        css="{0: 'EXT:my_site/Resources/Public/Build/main.css'}"
        js="{0: 'EXT:my_site/Resources/Public/Build/main.js'}">
        <main class="page-content">
            <my:element.textmedia record="{data}" />
        </main>
    </look:backend.contentPreview>
</f:section>
</html>
Copied!

Three things are worth noting:

  • <f:layout name="Preview" /> with a Content section is the layout Content Blocks provides for backend previews. Without it, Content Blocks renders the template three times (header, content, footer) and the preview appears three times.
  • The markup inside the view helper is whatever your frontend template produces. Here it is a Fluid component that receives the record; it could just as well be a partial or plain HTML. Wrapping the element in the same container markup as the frontend (<main class="page-content">) makes sure the grid and spacing rules of your CSS apply.
  • css and js take the assets of your frontend build. They are loaded inside the preview frame only, never in the backend itself.
A content element with a coloured section background rendered in the page module

Section backgrounds, decorative borders and buttons come from the site's own stylesheet.

Previews for classic content elements 

Content element types without Content Blocks can use the view helper in the Fluid template that TYPO3 renders for the page module preview. Register the template with page TSconfig:

EXT:my_site/Configuration/page.tsconfig
mod.web_layout.tt_content.preview.textmedia = EXT:my_site/Resources/Private/Templates/Preview/Textmedia.html
Copied!

The template receives the raw database row as {record} and can wrap its rendering in the view helper the same way:

EXT:my_site/Resources/Private/Templates/Preview/Textmedia.html
<html data-namespace-typo3-fluid="true"
      xmlns:f="http://typo3.org/ns/TYPO3/CMS/Fluid/ViewHelpers"
      xmlns:look="http://typo3.org/ns/Flowd/Typo3Look/ViewHelper">
<look:backend.contentPreview
    css="{0: 'EXT:my_site/Resources/Public/Css/main.css'}">
    <f:render partial="Content/Textmedia" arguments="{record: record}" />
</look:backend.contentPreview>
</html>
Copied!

See the TSconfig reference for the details of mod.web_layout.tt_content.preview.

The view helper 

<look:backend.contentPreview
    scale="0.6"
    height="400"
    bodyClass="application"
    css="{0: 'EXT:my_site/Resources/Public/Build/main.css'}"
    js="{0: 'EXT:my_site/Resources/Public/Build/main.js'}">
    <!-- frontend markup -->
</look:backend.contentPreview>
Copied!
Name Type Default
float extension configuration contentPreview.scale (0.5)
integer extension configuration contentPreview.height (0)
string (empty)
array []
array []
scale
Type
float
Default
extension configuration contentPreview.scale (0.5)

Factor the frontend is scaled down with inside the preview. 0.5 shows the site at half size, 1 at its natural size. The frame is always as wide as the page module column; the scale decides how much of the frontend width fits into it.

height
Type
integer
Default
extension configuration contentPreview.height (0)

Maximum height of the preview in pixels. Elements that are taller are cut off and fade out at the bottom, so editors see that there is more. 0 means no limit: the frame grows with its content.

A preview cut off at a fixed height with a fade-out at the bottom

A preview with height="250". The fade-out marks that the element continues below.

bodyClass
Type
string
Default
(empty)

Class attribute of the <body> inside the preview frame. Use it when your stylesheet expects a class on the body, for example a theme or a scope class.

css
Type
array
Default
[]

Stylesheets to load inside the frame, as EXT: paths or public URLs. Usually the CSS bundle of your frontend build. Look's own small stylesheet (scaling, fade-out) is always loaded first.

js
Type
array
Default
[]

JavaScript modules to load inside the frame, as EXT: paths or public URLs. They are loaded as <script type="module"> and only when the feature flag allowSiteScripts is enabled. Without it the previews show the static markup with CSS only.

Assets registered by the content 

Templates and components inside the preview may register their own assets with the standard Fluid view helpers <f:asset.css> and <f:asset.script>. Look collects those while rendering the content and puts them into the head of the preview frame. They never reach the backend page, and they never leak into the preview of another content element.

A component that brings its own stylesheet
<f:asset.css identifier="my-slider" href="EXT:my_site/Resources/Public/Css/slider.css" />
<f:asset.script identifier="my-slider" src="EXT:my_site/Resources/Public/JavaScript/slider.js" />
<div class="slider">...</div>
Copied!

Scripts registered this way follow the same rule as the js argument: they load only when allowSiteScripts is enabled, and they get the nonce of the backend request so the preview's Content Security Policy accepts them.

When rendering fails 

If the frontend markup cannot be rendered (a missing partial, a PHP error in a view helper), Look shows a red callout in place of the preview instead of breaking the page module. In development context, or with backend debugging enabled, the callout contains the error message; in production it names only the error code and the message goes to the TYPO3 log. Fix the template and reload the page module; there is nothing to clear.

Tips for good previews 

Render inside the frontend container

Put the element into the same wrapper markup as the frontend page (content container, grid). Otherwise widths, gutters and backgrounds look different from the website.

A contact form element rendered in the page module

A form element with the site's containers and spacing: the preview matches the website because it uses the same wrapper markup.

Choose one scale for the whole site
Set the scale once in the extension configuration and leave the argument out of the templates. Editors get a consistent zoom level across all element types.
Limit the height of long elements
A list or a slider with dozens of items makes the page module very long. Give those element types a height, the fade-out tells editors the element continues.
Keep hidden things hidden
The backend shows hidden relations by default. If your frontend hides unpublished images or child records, make the preview do the same, for example by resetting the visibility aspect of the TYPO3 context while rendering the preview. Otherwise editors see a layout the website never shows.

Configuration 

Look works without any configuration. Two kinds of settings exist: defaults for the appearance of the previews (extension configuration) and switches that grant the previews additional capabilities (feature flags).

Extension configuration 

Open Admin Tools > Settings > Extension Configuration and choose look. The values are used whenever the view helper is called without the corresponding argument.

The extension configuration of look with the fields default scale and default maximum height

Default scale and default maximum height in the extension configuration.

Name Type Default
string (decimal number) 0.5
positive integer 0
contentPreview.scale
Type
string (decimal number)
Default
0.5

Factor all previews are scaled down with unless a template sets its own scale. 0.5 shows the frontend at half size, 0.6 at 60 percent, 1 at full size.

A good starting point is the width of your page module divided by the width of your frontend layout. With a 1200 pixel wide frontend and a page module column of about 700 pixels, 0.6 shows the whole width of the site.

contentPreview.height
Type
positive integer
Default
0

Maximum height of all previews in pixels unless a template sets its own height. Taller elements are cut off with a fade-out. 0 means no limit.

The same values can be set in config/system/settings.php or additional.php, for example in a deployment:

config/system/settings.php (excerpt)
'EXTENSIONS' => [
    'look' => [
        'contentPreview' => [
            'scale' => '0.6',
            'height' => '0',
        ],
    ],
],
Copied!

Feature flags 

The preview frame is locked down by default (see Security). Two feature flags open it up step by step, a third adds an editing shortcut. All are off unless you enable them, and enabling a flag always means giving the preview an additional capability.

Set them in config/system/settings.php or additional.php:

config/system/additional.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['look.contentPreview.allowSiteScripts'] = true;
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['look.contentPreview.allowMedia'] = true;
$GLOBALS['TYPO3_CONF_VARS']['SYS']['features']['look.contentPreview.editOverlay'] = true;
Copied!

Sandbox capabilities 

look.contentPreview.allowSiteScripts
Default
false

Loads the JavaScript of your site inside the previews: the modules of the js argument and scripts registered with <f:asset.script>.

Off: the previews show the static markup with CSS only. Sliders show all slides, masonry grids fall back to their CSS layout, tabs show their first pane. Look's own small script for the frame height still runs.

On: the site scripts run inside the frame, so interactive elements look like on the website. The scripts run in the isolated frame and cannot reach the backend, but they do execute, so only enable the flag for a frontend build you trust.

look.contentPreview.allowMedia
Default
false

Loads video and audio files and embedded players inside the previews.

Off: the preview document carries a Content Security Policy that blocks media files and embedded frames (YouTube, Vimeo, ...), so opening the page module does not download videos. Videos show as striped placeholder boxes in the size the layout reserves for them (Firefox and Safari keep their play button on top of the box).

A text and media element whose video shows as a striped placeholder box in the preview

A content element with a video while media are blocked: the layout is complete, the video area is a placeholder.

On: the media files load and the first frame of a video is shown; embedded players load as far as the backend Content Security Policy allows their host. Autoplay still does not happen inside the page module, the TYPO3 backend does not grant that permission to embedded frames.

Edit overlay 

look.contentPreview.editOverlay
Default
false

Turns every preview into a shortcut for editing. Editors who hover a preview see a pencil icon in a circle, the same icon as in the element header, and a click behaves exactly like that header button: on TYPO3 14.3 and later the contextual edit panel slides in from the side, on older versions, which do not know the panel, the classic edit form opens. Editors who switched the contextual panel off in their user settings get the classic form here as well.

A preview with the hover overlay showing a pencil icon in a circle

Hovering a preview with the edit overlay enabled.

The overlay only appears for users who are allowed to edit the element. Look applies the same rules as the edit button in the element header: administrators always see it; everybody else needs modify access to the table, content edit permission on the page, a page that is not locked for editing, and edit access to the record (table, language, record lock). Users without these rights get the plain preview, so nobody is offered an action they cannot perform.

Look finds the record on its own from the template variables: the data object of a Content Blocks preview or the record array of a classic preview template. Nothing has to be passed to the view helper.

After changing the configuration 

Extension configuration and feature flags are read on every request, the previews themselves are rendered on every load of the page module. Reload the page module after a change; no cache needs to be flushed.

Security 

A preview shows content that editors wrote, rendered with templates and scripts of the frontend, inside the backend of the site. Look treats that content as untrusted and isolates every preview as far as browsers allow. This chapter explains what is in place and what it means for you.

The preview frame is sandboxed 

Every preview is an <iframe> with the sandbox attribute set to allow-scripts and nothing else. Browsers then give the frame an opaque origin: the content behaves as if it came from an unknown, foreign website.

Concretely, content inside a preview

  • cannot access the backend: no access to the TYPO3 backend document, the editor's session cookie, local storage or session storage;
  • cannot navigate or open windows: no links to follow, no popups, no redirects of the backend;
  • cannot submit forms: a contact form in the preview is just markup;
  • cannot show dialogs: no alert(), no download prompts;
  • cannot be clicked: the frame ignores pointer events, the editor's clicks go to the page module controls as usual.

The referrerpolicy is no-referrer, so requests from the frame carry no backend URL.

Scripts are limited by a Content Security Policy 

Scripts may run inside the frame, otherwise Look could not report the content height to the page module. Which scripts run is decided by a Content Security Policy in the preview document:

script-src 'nonce-<nonce of the backend request>' 'strict-dynamic'
Copied!

Only script tags that Look itself writes into the document carry that nonce: its own height script and, with allowSiteScripts, the scripts of your frontend build. A <script> that arrives inside the content, for example through an unsafe rich text field, has no nonce and is refused by the browser. 'strict-dynamic' lets the trusted scripts import their own modules.

Media are blocked by default 

Unless allowMedia is enabled, the same policy also contains media-src 'none'; frame-src 'none'. Video and audio files are neither downloaded nor played while the page module is open, and embedded players (YouTube, Vimeo and other iframes) are not loaded either; videos appear as striped placeholder boxes. Besides bandwidth this avoids a page module full of playing videos.

The preview document also inherits the Content Security Policy of the TYPO3 backend. Its default only allows assets from the backend's own host, so external fonts, libraries or images need an explicit extension of that policy, see Assets from other hosts do not load.

No permissions 

Camera, microphone, geolocation, fullscreen, autoplay and the other browser permissions are not available to the frame. The TYPO3 backend does not grant them to embedded frames, and the opaque origin of the sandbox denies the rest.

What this means for you 

Enable feature flags deliberately
The defaults give previews no capabilities beyond CSS. Enabling allowSiteScripts runs your frontend build inside the frame. It stays isolated from the backend, but review what the build does (tracking, external requests) before enabling it.
Web fonts need a CORS header
The opaque origin makes web fonts and script modules cross-origin requests. Look's own script is a classic script and works without any server configuration, but your frontend fonts only load if the server answers with Access-Control-Allow-Origin: * for their path, see If your frontend uses web fonts. The header is standard practice for public static files and exposes nothing the files did not expose before.
Some frontend techniques need adjustments
External SVG sprites (<use href="...svg#icon">) cannot load inside an opaque origin, see SVG icons are missing. Scripts running in the frame (with allowSiteScripts) have no sessionStorage or localStorage and cannot autoplay media; guard such calls in your frontend code as you would for private browsing modes.

Known problems and how to solve 

Most problems come from the isolation of the preview frame. The frame has an opaque origin, which changes how browsers treat a few frontend techniques. This chapter lists the symptoms and the fixes.

The previews stay empty on a password-protected site 

Symptom: the website asks for a user name and password before it shows anything (HTTP Basic Auth, common on staging and preview servers). In the page module every Look preview is an empty box, about 150 pixels high, with no styling and no images. The browser console reports 401 errors for the files inside the frame.

Cause: this is intended. The preview frame is deliberately isolated from the backend, see Security. The browser treats it like a page from an unknown website: it has no login of any kind, neither your TYPO3 session nor the password you typed into the browser's prompt. Every stylesheet, script and image the frame requests is therefore refused by the server, and browsers do not show a password prompt for such requests.

It is the same wall that protects your session. Nothing rendered inside a preview can reach the backend, and in return the preview cannot borrow the backend's credentials. Look has no switch to open that wall, because opening it would give preview content the same access to the backend that you have.

What you can do: nothing inside TYPO3, this is a property of the server setup. The previews work on every installation that is reachable without a password prompt, which is the normal case for a live site.

In theory the server could be configured to deliver the static files the previews need (stylesheets, scripts, images, fonts) without asking for the password, while the pages themselves stay protected. Be aware of what that means: depending on how it is done, those files become publicly readable for anyone who knows or guesses their address, including uploaded images and documents. Whether that is acceptable has to be decided per project. Look neither recommends nor documents such a setup; if it is done, it is entirely the responsibility of the people operating the server.

Assets from other hosts do not load 

Symptom: web fonts from Google Fonts, a library from a CDN or images from an external server are missing in the preview, while they work on the website. The console reports a Content Security Policy violation, not a CORS error.

Cause: the preview document inherits the Content Security Policy of the TYPO3 backend, which by default only allows assets from the backend's own host. Adding a CORS header does not help here, the browser refuses the request before it is sent.

Fix: serve the assets from your own host, or extend the backend policy for the hosts you trust with a Configuration/ContentSecurityPolicies.php in your site package:

EXT:my_site/Configuration/ContentSecurityPolicies.php
<?php

use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Directive;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Mutation;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationCollection;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\MutationMode;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\Scope;
use TYPO3\CMS\Core\Security\ContentSecurityPolicy\UriValue;
use TYPO3\CMS\Core\Type\Map;

return Map::fromEntries([
    Scope::backend(),
    new MutationCollection(
        new Mutation(MutationMode::Extend, Directive::FontSrc, new UriValue('https://fonts.gstatic.com')),
        new Mutation(MutationMode::Extend, Directive::StyleSrc, new UriValue('https://fonts.googleapis.com')),
    ),
]);
Copied!

See the Content Security Policy chapter of the core API reference for the details.

Fonts or scripts do not load 

Symptom: the preview uses fallback fonts, or with allowSiteScripts the site scripts do not run. The browser console inside the frame reports a CORS error.

Cause: web fonts and JavaScript modules are loaded as cross-origin requests from the frame. The web server does not send Access-Control-Allow-Origin: * for them. Look's own script is not affected, it is a classic script.

Fix: add the header for the path your frontend build lives in, see If your frontend uses web fonts.

SVG icons are missing 

Symptom: icons referenced as an external SVG sprite are blank. The console says "Unsafe attempt to load URL ... from frame with URL about:srcdoc".

Cause: <svg><use href="/icons.svg#play"> may only load files from the same origin, and the frame has none.

Fix: inline the SVG when rendering for the preview. A small view helper that reads the icon file and returns its markup does the job. Detect the preview context in your templates, for example with a flag your preview template sets, and switch between the sprite reference (frontend) and the inline markup (preview):

<f:if condition="{isBackendPreview}">
    <f:then>{my:svg.inline(path: 'EXT:my_site/Resources/Public/Icons/{name}.svg', class: 'icon')}</f:then>
    <f:else>
        <svg class="icon"><use href="{f:uri.resource(path: 'EXT:my_site/Resources/Public/Icons/{name}.svg')}#icon"></use></svg>
    </f:else>
</f:if>
Copied!

Icons that are inlined in the frontend anyway need no change.

The preview appears three times 

Symptom: with Content Blocks, the whole preview is repeated three times.

Cause: Content Blocks renders backend-preview.html for the header, the content and the footer of the element.

Fix: use the Preview layout with a Content section, see Previews for Content Blocks.

Images are missing, "File ... does not exist" 

Symptom: the preview shows broken images or an error about a processed file that does not exist.

Cause: backend requests defer image processing to a later request. A frontend template that expects the processed file immediately (for example a custom picture renderer) does not get it.

Fix: set the fileProcessing aspect of the TYPO3 context to non-deferred (new FileProcessingAspect(false)) while rendering the preview, in the same wrapper that handles the visibility aspect.

A red callout instead of the preview 

Symptom: the page module shows "Preview could not be rendered" with an error message and a code.

Cause: rendering the frontend markup threw an exception.

Fix: in development context (or with backend debugging enabled) the callout names the problem, usually a missing partial, a wrong argument or a PHP error in a view helper; in production it shows only the error code and the details go to the TYPO3 log. Correct the template and reload the page module.

Nothing works in the standalone Install Tool 

The previews need the nonce of a backend request. The standalone Install Tool (/typo3/install.php) has none and does not render page module previews, which is expected.

Sitemap 

.. sitemap::