Helpers
Fluid ViewHelpers and Handlebars helpers serve the same role: they bring PHP logic into templates. The implementation model is different enough to warrant a dedicated page.
ViewHelpers vs. Helpers
A Fluid ViewHelper is a PHP class that implements
\TYPO3Fluid\. Arguments are
declared via
initialize and the class is resolved by its
namespace prefix (e.g.,
f:,
myext:).
A Handlebars helper is any PHP callable registered via the :php: #
attribute. Arguments reach the callable either as named hash arguments
(name=value pairs after the helper name) or as positional arguments
(bare values in order). There is no argument declaration step — the method
signature is the contract.
| Fluid ViewHelper | Handlebars helper |
|---|---|
Class extending
Abstract | Any class / method / callable |
| Namespace prefix in template | Plain identifier string |
initialize | Method parameters |
render |
$options->fn |
| Registered via namespace import |
# attribute |
Porting an inline ViewHelper
Inline ViewHelpers that transform a single value (like
<f:)
are the most common case. The Handlebars equivalent is a helper that receives the
value as a positional argument and returns the formatted string.
Fluid:
<f:format.date format="d.m.Y">{date}</f:format.date>
{date -> f:format.date(format: 'd.m.Y')}
Handlebars:
{{formatDate date format="d.m.Y"}}
Helper implementation:
namespace Vendor\Extension\Renderer\Helper;
use CPSIT\Typo3Handlebars\Attribute\AsHelper;
use DevTheorem\Handlebars\HelperOptions;
#[AsHelper('formatDate')]
final readonly class FormatDateHelper
{
public function __invoke(HelperOptions $options, ?\DateTimeInterface $date = null): ?string
{
$format = is_string($options->hash['format'] ?? null)
? $options->hash['format']
: 'd.m.Y';
return $date?->format($format);
}
}
Porting a block / wrapping ViewHelper
ViewHelpers that wrap inner content (block ViewHelpers) correspond to
Handlebars block helpers. The inner content is rendered via
$options->fn and the inverse ({)
branch via
$options->inverse.
Fluid:
<myext:ifGranted role="ADMIN">
<a href="/admin">Admin panel</a>
</myext:ifGranted>
Handlebars:
{{#ifGranted role="ADMIN"}}
<a href="/admin">Admin panel</a>
{{/ifGranted}}
Helper implementation:
namespace Vendor\Extension\Renderer\Helper;
use CPSIT\Typo3Handlebars\Attribute\AsHelper;
use DevTheorem\Handlebars\HelperOptions;
use Vendor\Extension\Security\AccessChecker;
#[AsHelper('ifGranted')]
final readonly class IfGrantedHelper
{
public function __construct(
private AccessChecker $accessChecker,
) {}
public function __invoke(HelperOptions $options): string
{
$role = $options->hash['role'] ?? '';
if ($this->accessChecker->isGranted((string)$role)) {
return (string)$options->fn($options->scope);
}
return (string)$options->inverse($options->scope);
}
}
Common ViewHelper equivalents
The table below lists frequently used Fluid ViewHelpers and how to handle them in Handlebars templates.
| Fluid ViewHelper | Handlebars approach |
|---|---|
f: | Built-in { / { |
f: | Built-in { |
f: | Built-in { |
f: | Triple-stash { |
f: | Default { (always escapes) |
f: | Custom format helper |
f: | Custom format helper |
f: | Custom translate helper (use TYPO3 API inside) |
f:,
f: | Custom URI helper (use
Uri inside) |
f: | Custom image helper (use TYPO3 image API inside) |
f: | { or { |
f: | Built-in { helper |
Fluid ViewHelper bridge
As a temporary migration aid, the extension ships a view
helper that invokes any registered Fluid ViewHelper directly from a Handlebars
template. This lets you use existing ViewHelpers without writing a wrapper immediately.
{{viewHelper "f:format.date" date=someDate format="d.m.Y"}}
{{viewHelper "myext:widget.paginate" objects=items as="pagedItems"}}
{{#viewHelper "myext:security.ifGranted" role="ADMIN"}}
<a href="/admin">Admin panel</a>
{{/viewHelper}}
To use ViewHelpers from a custom namespace, register the namespace first with
view:
{{viewHelperNamespace "tx" "https://typo3.org/ns/Vendor/Extension/ViewHelpers"}}
{{viewHelper "tx:myHelper" someArg=value}}
Important
The view helper is intended as a short-term escape
hatch during migration, not as a permanent pattern. It carries the overhead
of bootstrapping a Fluid rendering context for every invocation and relies on
internal Fluid APIs that may change. Replace it with a proper Handlebars
helper once the migration for the affected template is complete.
See also
Custom helpers — full reference for implementing and registering Handlebars helpers.