diff --git a/Documentation/ApiOverview/Fluid/DevelopCustomViewhelper.rst b/Documentation/ApiOverview/Fluid/DevelopCustomViewhelper.rst
new file mode 100644
index 0000000000..887c74a690
--- /dev/null
+++ b/Documentation/ApiOverview/Fluid/DevelopCustomViewhelper.rst
@@ -0,0 +1,600 @@
+.. include:: /Includes.rst.txt
+.. index::
+ ViewHelpers; Custom
+ Fluid; Custom ViewHelpers
+.. _fluid-custom-viewhelper:
+
+==============================
+Developing a custom ViewHelper
+==============================
+
+This chapter will demonstrate how to write a custom Fluid ViewHelper in TYPO3.
+
+A "Gravatar" ViewHelper is created, which uses an email address as parameter
+and shows the picture from gravatar.com if it exists.
+
+The official documentation of Fluid for writing custom ViewHelpers can be found
+within Fluid documentation at
+https://github.com/TYPO3/Fluid/blob/master/doc/FLUID_CREATING_VIEWHELPERS.md.
+
+.. contents:: Contents of this page
+ :local:
+ :depth: 2
+
+
+Fluid
+=====
+
+The custom ViewHelper is not part of the default distribution. Therefore a
+namespace import is necessary to use this ViewHelper. In the following example,
+the namespace :php:`\MyVendor\BlogExample\ViewHelpers` is imported with the
+prefix `blog`. Now, all tags starting with `blog:` are interpreted as
+ViewHelper from within this namespace:
+
+.. code-block:: html
+ :caption: EXT:blog_example/Resources/Private/Templates/SomeTemplate.html
+
+ {namespace blog=MyVendor\BlogExample\ViewHelpers}
+
+For further information about namespace import, see
+:ref:`fluid-syntax-viewhelpers-import-namespaces`.
+
+The ViewHelper should be given the name "gravatar" and only take an email
+address as a parameter. The ViewHelper is called in the template as follows:
+
+.. code-block:: html
+ :caption: EXT:blog_example/Resources/Private/Templates/SomeTemplate.html
+
+
+
+See :ref:`global-namespace-import` for information how to import
+namespaces globally.
+
+AbstractViewHelper implementation
+=================================
+
+Every ViewHelper is a PHP class. For the Gravatar ViewHelper, the name of the
+class is :php:`\MyVendor\BlogExample\ViewHelpers\GravatarViewHelper`.
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+ :linenos:
+
+ registerArgument('emailAddress', 'string', 'The email address to resolve the gravatar for', true);
+ }
+
+ public static function renderStatic(
+ array $arguments,
+ \Closure $renderChildrenClosure,
+ RenderingContextInterface $renderingContext
+ ) {
+ // this is improved with the TagBasedViewHelper (see below)
+ return '';
+ }
+ }
+
+:php:`AbstractViewHelper`
+-------------------------
+
+*line 7*
+
+Every ViewHelper must inherit from the class
+:php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper`.
+
+A ViewHelper can also inherit from subclasses of :php:`AbstractViewHelper`, e.g.
+from :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper`.
+Several subclasses are offering additional functionality. The
+:php:`TagBasedViewHelper` will be explained :ref:`later on in this chapter
+` in detail.
+
+.. _fluid-viewhelper-custom-escaping-of-output:
+
+Escaping of output
+------------------
+
+*line 11*
+
+Setting the property :php:`$escapeOutput` to false is necessary to prevent
+escaping of output.
+
+By default, all output is escaped by :php:`htmlspecialchars` to prevent cross
+site scripting.
+
+If escaping of children is disabled, no nodes passed with inline
+syntax or values used as tag content will be escaped. Note that
+:php:`$escapeOutput` takes priority: if it is disabled, escaping child nodes
+is also disabled unless explicitly enabled.
+
+Passing in children is explained in :ref:`prepare-viewhelper-for-inline-syntax`.
+
+.. _fluid-viewhelper-custom-initializeArguments:
+
+:php:`initializeArguments()`
+----------------------------
+
+*line 13*
+
+The :php:`Gravatar` ViewHelper must hand over the email address which
+identifies the Gravatar. Every ViewHelper has to declare which parameters are
+accepted explicitly. The registration happens inside :php:`initializeArguments()`.
+
+In the example above, the ViewHelper receives the argument `emailAddress` of
+type `string`. These arguments can be accessed
+through the array :php:`$arguments`, which is passed into the :php:`renderStatic()`
+method (see :ref:`next section `).
+
+.. tip::
+
+ Sometimes arguments can take various types. In this case, the type `mixed`
+ should be used.
+
+.. _fluid-viewhelper-custom-renderStatic:
+
+:php:`renderStatic()`
+---------------------
+
+*line 19*
+
+The method :php:`renderStatic()` is called once the ViewHelper is rendered. The
+return value of the method is rendered directly.
+
+* line 9*
+
+The trait :php:`CompileWithRenderStatic` must be used if the class implements
+:php:`renderStatic()`.
+
+.. _creating-xml-tags-using-tagbasedviewhelper:
+.. _creating-html-tags-using-tagbasedviewhelper:
+
+Creating HTML/XML tags with the :php:`AbstractTagBasedViewHelper`
+=================================================================
+
+For ViewHelpers which create HTML/XML tags, Fluid provides an enhanced base
+class: :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper`. This
+base class provides an instance of
+:php:`\TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder` that can be used to create
+HTML-tags. It takes care of the syntactically correct creation and, for example,
+escapes single and double quotes in attribute values.
+
+.. attention::
+
+ Correctly escaping the attribute values is mandatory as it affects security
+ and prevents cross-site scripting attacks.
+
+Because the Gravatar ViewHelper creates an :html:`img` tag the use of the
+:php:`\TYPO3Fluid\Fluid\Core\ViewHelper\TagBuilder` is advised:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+ :linenos:
+
+ registerUniversalTagAttributes();
+ $this->registerTagAttribute('alt', 'string', 'Alternative Text for the image');
+ $this->registerArgument('emailAddress', 'string', 'The email address to resolve the gravatar for', true);
+ }
+
+ public function render()
+ {
+ $this->tag->addAttribute(
+ 'src',
+ 'http://www.gravatar.com/avatar/' . md5($this->arguments['emailAddress'])
+ );
+ return $this->tag->render();
+ }
+ }
+
+What is different in this code?
+
+The attribute :php:`$escapeOutput` is no longer necessary.
+
+:php:`AbstractTagBasedViewHelper`
+---------------------------------
+
+*line 6*
+
+The ViewHelper does not inherit directly from :php:`AbstractViewHelper` but
+from :php:`AbstractTagBasedViewHelper`, which provides and initializes the tag builder.
+
+:php:`$tagName`
+---------------
+
+*line 8*
+
+There is a class property :php:`$tagName` which stores the name of the tag to be
+created (:html:``).
+
+:php:`$this->tag->addAttribute()`
+---------------------------------
+
+*line 20*
+
+The tag builder is available at property :php:`$this->tag`. It offers the method
+:php:`addAttribute()` to add new tag attributes. In our example the attribute
+`src` is added to the tag.
+
+:php:`$this->tag->addAttribute()`
+---------------------------------
+
+*line 24*
+
+The GravatarViewHelper creates an img tag builder, which has a method named
+:php:`render()`. After configuring the tag builder instance, the rendered tag
+markup is returned.
+
+.. note::
+
+ As :php:`$this->tag` is an object property, :php:`render()` is used to
+ generate the output. :php:`renderStatic()` would have no access. For further
+ information take a look at :ref:`the-different-render-methods`.
+
+:php:`$this->registerTagAttribute()`
+------------------------------------
+
+Furthermore the :php:`TagBasedViewHelper` offers assistance for ViewHelper
+arguments that should recur directly and unchanged as tag attributes. These
+must be registered with the method :php:`$this->registerTagAttribute()`
+within :php:`initializeArguments`.
+If support for the :html:`` attribute :html:`alt`
+should be provided in the ViewHelper, this can be done by initializing this in
+:php:`initializeArguments()` in the following way:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+
+ public function initializeArguments()
+ {
+ // registerTagAttribute($name, $type, $description, $required = false)
+ $this->registerTagAttribute('alt', 'string', 'Alternative Text for the image');
+ }
+
+For registering the universal attributes id, class, dir, style, lang, title,
+accesskey and tabindex there is a helper method
+:php:`registerUniversalTagAttributes()` available.
+
+If support for universal attributes should be provided and in addition to the
+`alt` attribute in the Gravatar ViewHelper the following
+:php:`initializeArguments()` method will be necessary:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+
+ public function initializeArguments()
+ {
+ parent::initializeArguments();
+ $this->registerUniversalTagAttributes();
+ $this->registerTagAttribute('alt', 'string', 'Alternative Text for the image');
+ }
+
+.. _insert-optional-arguments:
+
+Insert optional arguments
+=========================
+
+An optional size for the image can be provided to the Gravatar ViewHelper. This
+size parameter will determine the height and width in pixels of the
+image and can range from 1 to 512. When no size is given, an image of 80px is
+generated.
+
+The :php:`render()` method can be improved like this:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+
+ public function initializeArguments()
+ {
+ $this->registerArgument('emailAddress', 'string', 'The email address to resolve the gravatar for', true);
+ $this->registerArgument('size', 'integer', 'The size of the gravatar, ranging from 1 to 512', false, 80);
+ }
+
+ public function render()
+ {
+ $this->tag->addAttribute(
+ 'src',
+ 'http://www.gravatar.com/avatar/' .
+ md5($this->arguments['emailAddress']) .
+ '?s=' . urlencode($this->arguments['size'])
+ );
+ return $this->tag->render();
+ }
+
+With this setting of a default value and setting the fourth argument to `false`,
+the `size` attribute becomes optional.
+
+.. _prepare-viewhelper-for-inline-syntax:
+
+Prepare ViewHelper for inline syntax
+====================================
+
+So far, the Gravatar ViewHelper has focused on the tag structure of the
+ViewHelper. The call to render the ViewHelper was written with tag syntax, which
+seemed obvious because it itself returns a tag:
+
+.. code-block:: html
+ :caption: EXT:blog_example/Resources/Private/Templates/SomeTemplate.html
+
+
+
+Alternatively, this expression can be written using the inline notation:
+
+.. code-block:: html
+ :caption: EXT:blog_example/Resources/Private/Templates/SomeTemplate.html
+
+ {blog:gravatar(emailAddress: post.author.emailAddress)}
+
+One should see the Gravatar ViewHelper as a kind of post-processor for an email
+address and would allow the following syntax:
+
+.. code-block:: html
+ :caption: EXT:blog_example/Resources/Private/Templates/SomeTemplate.html
+
+ {post.author.emailAddress -> blog:gravatar()}
+
+This syntax places focus on the variable that is passed to the ViewHelper as it
+comes first.
+
+The syntax `{post.author.emailAddress -> blog:gravatar()}` is an alternative
+syntax for `{post.author.emailAddress}`. To
+support this, the email address comes either from the argument `emailAddress`
+or, if it is empty, the content of the tag should be interpreted as email
+address.
+
+This is typically used with formatting ViewHelpers. These ViewHelpers all
+support both tag mode and inline syntax.
+
+Depending on the implemented method for rendering, the implementation is
+different:
+
+.. _with-renderstatic:
+
+With :php:`renderStatic()`
+--------------------------
+
+To fetch the content of the ViewHelper, the argument
+:php:`$renderChildrenClosure` is available. This returns the evaluated object
+between the opening and closing tag.
+
+Lets have a look at the new code of the :php:`renderStatic()` method:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+
+ registerArgument('emailAddress', 'string', 'The email address to resolve the gravatar for');
+ }
+
+ public static function renderStatic(
+ array $arguments,
+ \Closure $renderChildrenClosure,
+ RenderingContextInterface $renderingContext
+ ) {
+ $emailAddress = $renderChildrenClosure();
+
+ return '';
+ }
+ }
+
+.. _with-render:
+
+With :php:`render()`
+--------------------
+
+To fetch the content of the ViewHelper the method :php:`renderChildren()` is
+available in the :php:`AbstractViewHelper`. This returns the evaluated object
+between the opening and closing tag.
+
+Lets have a look at the new code of the :php:`render()` method:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/GravatarViewHelper.php
+
+ registerArgument('emailAddress', 'string', 'The email address to resolve the gravatar for', false, null);
+ }
+
+ public function render()
+ {
+ $emailAddress = $this->arguments['emailAddress'] ?? $this->renderChildren();
+
+ $this->tag->addAttribute(
+ 'src',
+ 'http://www.gravatar.com/avatar/' . md5($emailAddress)
+ );
+
+ return $this->tag->render();
+ }
+ }
+
+
+
+.. _handle-additional-arguments:
+
+Handle additional arguments
+===========================
+
+If a ViewHelper allows further arguments which have not been explicitly
+configured, the :php:`handleAdditionalArguments()` method can be implemented.
+
+The :php:`\TYPO3Fluid\Fluid\Core\ViewHelper\AbstractTagBasedViewHelper` makes use
+of this, to allow setting any `data-` argument for tag based ViewHelpers.
+
+The method will receive an array of all arguments, which are passed in addition
+to the registered arguments. The array uses the argument name as the key and the
+argument value as the value. Within the method, these arguments can be handled.
+
+For example, the :php:`AbstractTagBasedViewHelper` implements the following:
+
+.. code-block:: php
+ :caption: EXT:fluid/Classes/ViewHelpers/AbstractTagBasedViewHelper.php
+
+ public function handleAdditionalArguments(array $arguments)
+ {
+ $unassigned = [];
+ foreach ($arguments as $argumentName => $argumentValue) {
+ if (strpos($argumentName, 'data-') === 0) {
+ $this->tag->addAttribute($argumentName, $argumentValue);
+ } else {
+ $unassigned[$argumentName] = $argumentValue;
+ }
+ }
+ parent::handleAdditionalArguments($unassigned);
+ }
+
+To keep the default behavior, all unwanted arguments should be passed to the
+parent method call :php:`parent::handleAdditionalArguments($unassigned);`, to
+throw exceptions accordingly.
+
+.. _the-different-render-methods:
+
+The different render methods
+============================
+
+ViewHelpers can have one or more of the following three methods for
+implementing the rendering. The following section will describe the differences
+between all three implementations.
+
+.. _compile-method:
+
+:php:`compile()`-Method
+-----------------------
+
+This method can be overwritten to define how the ViewHelper should be compiled.
+That can make sense if the ViewHelper itself is a wrapper for another native PHP
+function or TYPO3 function. In that case, the method can return the call to this
+function and remove the need to call the ViewHelper as a wrapper at all.
+
+The :php:`compile()` has to return the compiled PHP code for the ViewHelper.
+Also the argument :php:`$initializationPhpCode` can be used to add further PHP
+code before the execution.
+
+.. note::
+
+ The :php:`renderStatic()` method still has to be implemented for the non
+ compiled version of the ViewHelper. In the future, this should no longer be
+ necessary.
+
+Example implementation:
+
+.. code-block:: php
+ :caption: EXT:blog_example/Classes/ViewHelpers/StrtolowerViewHelper.php
+
+ registerArgument('string', 'string', 'The string to lowercase.', true);
+ }
+
+ public static function renderStatic(
+ array $arguments,
+ \Closure $renderChildrenClosure,
+ RenderingContextInterface $renderingContext
+ ) {
+ return strtolower($arguments['string']);
+ }
+
+ public function compile(
+ $argumentsName,
+ $closureName,
+ &$initializationPhpCode,
+ ViewHelperNode $node,
+ TemplateCompiler $compiler
+ ) {
+ return 'strtolower(' . $argumentsName. '[\'string\'])';
+ }
+ }
+
+.. _renderstatic-method:
+
+:php:`renderStatic()`-Method
+----------------------------
+
+Most of the time, this method is implemented. It's the one that is called by
+default from within the compiled Fluid.
+
+It is, however, not called on AbstractTagBasedViewHelper implementations. With these classes
+you still need to use the :php:`render()` method since that is the only way you can access :php:`$this->tag`
+which contains the tag builder that generates the actual XML tag.
+
+As this method has to be static, there is no access to object properties such as
+:php:`$this->tag` (in a subclass of :php:`AbstractTagBasedViewHelper`) from within
+:php:`renderStatic`.
+
+.. note::
+
+ This method can not be used when access to child nodes is necessary. This is
+ the case for ViewHelpers like `if` or `switch` which need to access their
+ children like `then` or `else`. In that case, :php:`render()` has to be used.
+
+.. _render-method:
+
+:php:`render()`-Method
+----------------------
+
+This method is the slowest one. Only use this method if it is necessary, for
+example if access to properties is necessary.
diff --git a/Documentation/ApiOverview/Fluid/Index.rst b/Documentation/ApiOverview/Fluid/Index.rst
index ae8a14a2c4..c457469eba 100644
--- a/Documentation/ApiOverview/Fluid/Index.rst
+++ b/Documentation/ApiOverview/Fluid/Index.rst
@@ -43,4 +43,5 @@ You can use Fluid in TYPO3 to do one of the following:
Introduction
Syntax
- ViewHelper reference
+ DevelopCustomViewhelper
+ ViewHelper reference