menu

AFX Template Language

React's JSX for Neos and PHP

Support the documentation

This documentation was written by volunteers. Please help support our effort:

Help us improve the documentation

Draft

This page is not yet fully completed - we are still working on the content here. Expect some rough edges 🙃

The Foundations of AFX

While Fusion can declare Tags and Contents and thus create all possible Markup the syntax to do this would be longish and also hard to read.

Instead you should use the AFX syntax to describe the markup you want to generate in way that strongly resembles the expected HTML but at the same time allows to user other Fusion prototypes aswell. Afx will afterwards be converted into Neos.Fusion:Tags including all properties and attributes you've passed to it. While writing this HTML-related markup, you have access to Neos variables, components, Eel helpers and of course Fusion.

Now, avoiding to go too much into depth about the technical aspects of how exactly AFX manages this miraculous transformation from HTML-like markdown to Fusion components, what you really need to know is the syntax.

NOTE: All examples in this section are taken from the blog article covering AFX and its development, history and implementation by Martin Ficzel.

HTML to Fusion in a Nutshell

In this section, you will learn how to write HTML-like markup that will then be processed into side-effect free, reusable Fusion components.

HTML-Tags (Tags without Namespace)

The HTML tags you write are transformed into Neos.Fusion:Tags objects, with all attributes you define being passed on accordingly. This means that the following block of AFX:

afx`
<h1 class="headline">{props.headline}</h1>
`

will be transpiled into this Fusion object:

Neos.Fusion:Tag {
    tagName = 'h1'
    attributes.class = 'headline'
    content = ${props.headline}
}

Fusion-Object-Tags (namespaced Tags)

Correspondingly, a namespaced tag will be transpiled into prototype names, while the attributes you pass on will be interpreted as top-level properties. This means that the following block of AFX:

afx`
  <Your.SitePackage:Prototype type="headline">
   {props.headline}
  </Your.SitePackage:Prototype>
`

will be transpiled into this Fusion object:

Your.SitePackage:Prototype {
    type = 'headline'
    content = ${props.headline}
}

Tag-Children

Depending on how many child nodes there are, AFX handles the rendering differently. Lets's look at the differences in transformation between having one child node versus multiple.

If there's exactly one child node, the following AFX:

afx`
<h1>{props.headline}</h1>
`

will be transpiled into this Fusion object:

Neos.Fusion:Tag {
    tagName = 'h1'
    content = ${props.headline}
}

However, if you nest more than one child node within your AFX-node, the following AFX:

afx`
  <h1>{props.title}: {props.subtitle}</h1>
`

will be transpiled into this Fusion object:

Neos.Fusion:Tag {
    tagName = 'h1'
    content = Neos.Fusion:Array {
        item_1 = {props.title}
        item_2 = ': '
        item_3 = ${props.subtitle}
    }
}

4. Meta-Attributes

As a rule, meta attributes are characterized by at @-sign. In your AFX markup, you can use them normally, as they will be applied to the transpiled into the resulting Fusion objects. This means you can use @if, @children or @key.

The following example shows how to render a headline only, if a headline is available. (Without the @if, the h1-tag would still be rendered, albeit empty.)

afx`
  <h1 @if.has={props.title}>{props.title}</h1>
`

This AFX markup will be transpiled into the following Fusion object:

Neos.Fusion:Tag {
    tagName = 'h1'
    @if.has={props.title}
    content = {props.title}
}

Another use case is the @children attribute. Using this, you can for instance map AFX children to the "itemRenderer" resulting in an iteration within a Neos.Fusion:Collection object.

You can see that done in this AFX markup:

afx`
<Neos.Fusion:Collection collection={['one','two','three']} @children="itemRender">
  <p>{item}</p>
</Neos.Fusion:Collection>
`

This will be transpiled into the following Fusion object:

Neos.Fusion:Collection {
    collection = ${['one','two','three']}
    itemRender = Neos.Fusion:Tag {
      tagName = 'p'
      content = ${item}  
    }
}

The @key attribute is somewhat of an exception. It can be used to define a name for an AFX child node if multiple children are rendered into a Neos.Fusion:Array object. However, this use case is discouraged as it breaks with the concept of encapsulating the presentational component.

5. Whitespace and Newlines

In the transformation process, AFX makes some simplifications, in order to streamline the generated Fusion output and to allow the developer to structure the notation in regards to the component hierarchy.

One of those ways of streamlining is the handling of white spaces. If you look at the following example, you will notice, that all white spaces that are connected to a new line are considered irrelevant and are consequently ignored in the output.

afx`
  <h1>
    {'eelExpression 1'}
    {'eelExpression 2'} 
  </h1>
`

This will be transpiled into the following Fusion object:

Neos.Fusion:Tag {
    tagName = 'h1'
    contents = Neos.Fusion:Array {
        item_1 = ${'eelExpression 1'}
        item_2 = ${'eelExpression 2'}   
    }
}

In contrast to this, all whitespaces within a single line are respected in the output. If you take the same Fusion as above but replace the line break with a space, the output will differ. Explicitly, the following AFX markup:

afx`
  <h1>
    {'eelExpression 1'}  {'eelExpression 2'}      
  </h1>
`

will be transpiled into this Fusion object:

Neos.Fusion:Tag {
    tagName = 'h1'
    contents = Neos.Fusion:Array {
        item_1 = ${'eelExpression 1'}        
        item_2 = ' '
        item_3 = ${'eelExpression 2'}   
    }
}

Hungry for More?

This summary doesn't come close to exhaustively describing the power you have at your fingertips when you use AFX. Instead it's aimed at giving you a first taste of the syntax and the underlying concept. For further information (partly by the original developers of AFX), take a look at the following sources: