---
title: "Template requirements"
manual: "Frontend Edit"
version: "2.6"
source: "Integration/TemplateRequirements.rst"
rendered: "2026-10-01T07:11:45+00:00"
---

# Template requirements {#template-requirements}

The extension has exactly **one** requirement of your templates: every content
element must be identifiable in the rendered HTML.

## The content element ID {#c-id}

Each content element needs a "c-id" — its UID prefixed with `c` — on the
element that wraps it:

**Rendered HTML of a content element**

```html
<div id="c10" class="frame frame-default frame-type-textpic">
    ...
</div>
```

This is how the injected JavaScript maps a DOM node to a database record. No
c-id means no edit button for that element.

**fluid_styled_content**

Nothing to do. `fluid_styled_content` renders the c-id out of the box,
so the extension works immediately after [Installation](../Installation/Index.html#installation).

**Custom templates**

Add the UID to the wrapping element yourself:

**EXT:my_sitepackage/Resources/Private/Templates/Content/Default.html**

```html
<div id="c{data.uid}">
    ...
</div>
```

**EXT:container**

[container](https://extensions.typo3.org/extension/container/)
templates do not render the c-id by default:

**Container template**

```html
<div id="c{data.uid}">
   <f:for each="{children_200}" as="record">
       <f:format.raw>{record.renderedContent}</f:format.raw>
   </f:for>
</div>
```

**EXT:dce**

[DCE](https://extensions.typo3.org/extension/dce) elements need the
c-id added to the
[DCE template](https://docs.typo3.org/p/t3/dce/main/en-us/UsersManual/Template.html):

**DCE template**

```html
<div class="dce" id="c{contentObject.uid}">
    Your template goes here...
</div>
```

> [!NOTE]
> Styling problems may occur with nested content elements, because the
> injected UI is positioned relative to the wrapping element.

## Alternative: the `data-frontend-edit` attribute {#data-frontend-edit-attribute}

For templates that cannot carry the c-id anchor - dynamic content element
extensions (DCE), other custom Fluid templates - a second matching channel
exists: a `data-frontend-edit="tt_content:{uid}"` attribute on the content
element's own wrapping HTML element.

**Example HTML output using the data attribute instead**

```html
<div data-frontend-edit="tt_content:10" class="my-custom-wrapper">
    ...
</div>
```

The bundled `xfe:editable` ViewHelper renders this attribute for you:

**Custom Fluid Template**

```html
{namespace xfe=Xima\XimaTypo3FrontendEdit\ViewHelpers}

<div class="my-custom-wrapper"{xfe:editable(record: data)}>
    ...
</div>
```

The ViewHelper renders only the attribute, so it goes inside the opening tag
in inline notation. The tag notation `<div <xfe:editable record="{data}" />>`
renders the same output, but it is not valid HTML and breaks IDEs, formatters
and linters.

Both patterns can be mixed freely on the same page; an element only needs one
of them. Unlike the c-id anchor pattern, a `data-frontend-edit` element is
always treated as the content element itself - no sibling resolution is
attempted.

## Alternative: render markers (experimental) {#render-markers}

Templates you cannot or do not want to change, e.g. Content Blocks without the
`fluid_styled_content` layout, can be detected through the site setting
[frontendEdit.markerBasedDetection](../Configuration/SiteSettings.html#confval-frontendedit-markerbaseddetection).
While it is active, every rendered content element is wrapped in a pair of HTML
comments:

**Rendered HTML with render markers**

```html
<!--xfe:b:tt_content:10-->
<div class="my-custom-wrapper">
    ...
</div>
<!--xfe:e:tt_content:10-->
```

The markers are an addition to the other two patterns. An element that
already has a c-id or a `data-frontend-edit` attribute keeps using it.

The output of the content element needs exactly **one** root element. With
several root elements, or with loose text next to the root element, the
markers cannot point at a single element and are ignored. The element's own
empty anchor is not counted, so the anchor pattern
`<a id="c10"></a><div>...</div>` works.

Two features still rely on the c-id and do not work for elements that are only
detected through markers or the `data-frontend-edit` attribute:

-   Jumping back to the element after saving
    ([frontendEdit.enableScrollToElement](../Configuration/SiteSettings.html#confval-frontendedit-enablescrolltoelement)), which uses the fragment
    `#c{uid}` of the return URL.
-   [Drag & Drop Reordering](../Usage/DragAndDrop.html#drag-and-drop), which collects the movable elements of a column by
    their c-id.

[Render markers](../Configuration/SetupRequirementsAndLimits.html#setup-render-markers) lists the operational limits, such as caching,
minifiers and non-HTML output.

## Editing foreign records (news, addresses, ...) {#editing-foreign-records}

The `data-frontend-edit` attribute also works for records from **any other
table** \- not just `tt_content` \- by adding a `table` prefix:
`data-frontend-edit="{table}:{uid}"`. This covers the classic case of
editing foreign records displayed on a detail page, e.g. a news detail page
rendered by EXT:news:

**News detail template (Detail.html)**

```html
{namespace xfe=Xima\XimaTypo3FrontendEdit\ViewHelpers}

<div class="news-detail"{xfe:editable(record: newsItem, table: 'tx_news_domain_model_news')}>
    <h1>{newsItem.title}</h1>
    ...
</div>
```

`record` takes a record array such as `{data}` or an object with a
`getUid()` method, such as an Extbase model or a core Record object.
Alternatively, pass the `uid` directly.

This is deliberately thin: the menu offers exactly **edit, info and
history** \- no hide, delete or move, since those are meaningful only for
tables this extension understands specifically (`tt_content`, `pages`).
Permissions are checked the same way as everywhere else in the extension (the
backend user's actual edit rights on that record); a table the current user
cannot edit - or that TYPO3 does not know at all - never gets a menu.
Translated records resolve to the current frontend language automatically,
the same way `tt_content` does.

Extend the menu the same way as for content elements, via the
[FrontendEditDropdownModifyEvent](../DeveloperCorner/Events.html#events) \- the record row carries a
`_table` key so a listener can tell it apart from a `tt_content` row.

## Optional markers {#template-requirements-optional}

Two features need additional markers in your templates. Both are opt-in — omit
them and the corresponding feature simply does not appear.

| Marker | Needed for |
| --- | --- |
| [ColumnTargetViewHelper](ColumnTargets.html#empty-columns) | "Create new content" buttons per column, and [Drag & Drop Reordering](../Usage/DragAndDrop.html#drag-and-drop) (drop targets cannot be resolved without it) |
| [Data ViewHelper](../DeveloperCorner/DataAttributes.html#data-attributes) | Edit links for related records inside a plugin, e.g. single news items in a list |

## What cannot be edited {#template-requirements-scope}

Only content elements belonging to the **current page** receive a menu.
Inherited content — a shared footer pulled in from another page, for example —
cannot be edited from the inheriting page. Use the
[toolbar](../Usage/Toolbar.html#toolbar) to jump to the page that owns the record.

> [!NOTE]
> **See also**
>
> -   [How it works](../DeveloperCorner/Architecture.html#how-it-works) — what happens on page load
> -   [FAQ](../FAQ/Index.html#faq) — troubleshooting when no menu appears
