Custom Rendering
The renderer API shipped since Foundry (v6) is at the same time more strict and more flexible. To get ready for this new API, you must understand some basics of the transient render tree produced by the TRE:
During the transient render tree generation, every DOM node is translated to a
TNode.
TTextnodes correspond to DOM Textnodes (anonymous TTextnodes) or DOM elements which children are DOM Textnodes (named TTextnodes). So a TTextnode cannot have children, and its content is a string accessible with the datafield.Thanks to hoisting,
TPhrasingnodes can only have TTextand TPhrasingnodes as children.
TBlocknodes can have any children.
You are kindly advised to read Transient Render Engine page before continuing!
Options for Custom Rendering
You can customize rendering at two steps of the flow:
During TRT generation. via HTML model definition.
At (React) render time via custom renderers.
These customizations are not exclusive, so you can use both approaches at the same time.
Model-based Custom Rendering
Example: Registering a New Tag
Let's say we have defined an advanced, powerful <blue-circle> Web Component for our website and we need to register a custom renderer for this tag. If we don't, the <blue-circle> elements will be translated to TEmpty and won't be rendered.
We must register an element model for this tag because it is non-standard.
Custom tags in HTML markup must never be self-closing. The HTML parser will not recognize non-void self-closing tags by default which will lead to unexpected outcomes.
We may register a custom component renderer, but this is not mandatory (see next chapter).
For a more detailed explanation of the allowed parameters for thefromCustomModelstatic method, see Transient Render Engine.
- JSX Source
- HTML Snippet
- TRT Snapshot
Example: Displaying Inline Images
In the below example, we are changing the element model of the<img> tag to support inline rendering. For this purpose, we take advantage of the customHTMLElementModels prop!
- JSX Source
- HTML Snippet
- TRT Snapshot
We used extend method to change the content model for the <img> tag. This method is immutable: it creates a new HTMLElementModel instance. It is thus safe to use this method to create models for new tags derived from models of existing tags.
You cannot set the contentModel dynamically. This is currently a limitation of the TRE.
Component-based Custom Rendering
Minimal Example
You can register custom renderers components with the renderers prop.
Stop talking, let's try it out. We're going to define a renderer for the <h1> element which supports press interactions:
- JSX Source
- HTML Snippet
- TRT Snapshot
The wrapper component injected when handling onPress for TBlock nodes is defined by the GenericPressable prop. You can also customize the highlight color with pressableHightlightColor. Also note that onPress works with textual nodes, in which case the eponym prop of React Native Text element will be used instead.
TDefaultRenderer can receive textProps prop which will be used when rendering a React Native Text element, and viewProps for View elements.
Children Tampering
Let's continue with a common requirement: injecting ads in the body of an article. More precisely, after the 2d and 4th children. To achieve our goal, we are going to use the TChildrenRenderer component:
- JSX Source
- HTML Snippet
- TRT Snapshot
The foundry API is powerful in terms of rendering customization. It is very easy to insert child elements, while preserving the internal rendering logic.
TChildrenRenderer can receive a renderChild prop to customize the rendering logic for each child.
Renderer Props Summary
A custom renderer will receive the below props:
The
TNodeto render.The default fallback renderer for this
TNode.The internal renderer for this
tagName. An internal renderer is like a custom renderer, but registered internally. If there is no internal renderer registered for this tag, InternalRendererwill be equal to TDefaultRenderer.The flatten style object which should be passed to the root element returned by this component.
To use when you render a
Text-based element (e.g. the typeprop is"text").To use when you render a
View-based element (e.g. the typeprop is"block").
typeTo check whether a
Text("text") or View("block") is expected as the root element returned by this component.Props passed directly from the parent custom renderer via
TChildrenRenderer. See propsForChildrenprop.The position relative to the parent React element, starting at 0.
The total number of children of this React element parent. e.g. number of React element siblings + 1.
See CustomRendererProps for a complete reference.