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 

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

Rendered HTML of a content element
<div id="c10" class="frame frame-default frame-type-textpic">
    ...
</div>
Copied!

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

Nothing to do. fluid_styled_content renders the c-id out of the box, so the extension works immediately after Installation.

Add the UID to the wrapping element yourself:

EXT:my_sitepackage/Resources/Private/Templates/Content/Default.html
<div id="c{data.uid}">
    ...
</div>
Copied!

container templates do not render the c-id by default:

Container template
<div id="c{data.uid}">
   <f:for each="{children_200}" as="record">
       <f:format.raw>{record.renderedContent}</f:format.raw>
   </f:for>
</div>
Copied!

DCE elements need the c-id added to the DCE template:

DCE template
<div class="dce" id="c{contentObject.uid}">
    Your template goes here...
</div>
Copied!

Alternative: the 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
<div data-frontend-edit="tt_content:10" class="my-custom-wrapper">
    ...
</div>
Copied!

The bundled <xfe:editable> ViewHelper renders this attribute for you:

Custom Fluid Template
{namespace xfe=Xima\XimaTypo3FrontendEdit\ViewHelpers}

<div class="my-custom-wrapper"<xfe:editable record="{data}" />>
    ...
</div>
Copied!

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.

Editing foreign records (news, addresses, ...) 

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)
{namespace xfe=Xima\XimaTypo3FrontendEdit\ViewHelpers}

<div class="news-detail"<xfe:editable record="{newsItem}" table="tx_news_domain_model_news" />>
    <h1>{newsItem.title}</h1>
    ...
</div>
Copied!

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 - the record row carries a _table key so a listener can tell it apart from a tt_content row.

Optional markers 

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 "Create new content" buttons per column, and Drag & Drop Reordering (drop targets cannot be resolved without it)
Data ViewHelper Edit links for related records inside a plugin, e.g. single news items in a list

What cannot be edited 

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 to jump to the page that owns the record.