After seven months of a long and exciting journey in alpha development and testing with the community, I am proud to announce the first Foundry (v6) beta release of React Native Render HTML.
This process has led the new API to mature, and the introduction of beta stage marks the end of its instability. During the beta stage, I will bring fixes to any issue reported by the community and expect the test coverage to rise above 90%. I also plan to refine the Discovery App and website, including additional sections for best user experience. Now, let's get to the heart of it!
Along with the release comes this new website and the Discovery App which features all the docs of the website with embedded RNRH-rendered snippets. For this very reason, the Discovery App is recommended for newcomers, or for those who want a "live" feeling of the new engine capabilities. The website is more suited during development when searching for specific information. In addition, the Discovery App has a collection of "Playgrounds" to play with specific components and observe how they respond to style and props changes.
The Transient Render engine (TRE) transforms DOM nodes into a ready-to-render
data structure called the Transient Render Tree (TRT), which is made of
TNodes. It allows features such as whitespace collapsing, hoisting,
CSS inheritance and more.
A legitimate concerns is whether it adds any overhead. The short answer is no, if we compare it to the legacy engine which had its own transient render structure. Moreover, this TRT construction process is benchmarked to safeguard its speed. In addition to the enumerated features, the new transient data structure offers obvious advantages for library consumers:
- It is totally transparent and predictable; you can create snapshots of a
TNodethanks to the
snaphot()method for an intuitive understanding of the engine internals. This feature is extremely handy for debugging and testing!
- It's hackable by allowing to define custom content models for tags. Say hi to inline images!
- It is shipped with a CSS processor which enforces strict translation rules from CSS to React Native styles. Say goodbye to native crashes caused by unsupported CSS properties! See the dedicated article for reference.
- It paves the way to server side (or build-time) pre-rendering in the future, and, why not, a react fiber and MDX builder.
Below is an example of HTML transformation into a Transient Render Tree:
The new rendering API is an order of magnitude more powerful than the legacy. Custom renderers are now plain React Component instead of functions, and you have now access to the underlying renderer for rich customization:
This custom renderer will insert an
AdComponent element after the second and
fourth children of this
Last but not least, custom renderers can reuse internal renderers (those
special renderers displaying lists, images and anchors). For this purpose,
you can use the
InternalRenderer prop or
font-family property allows a comma-separated list of fonts, while react
fontFamily does not. Moreover, setting a font that is not available in
the system will often lead to native crashes. To reconcile this inconsistency, the CSS
Processor will try to match each font in a
font-family property with a list
of supported fonts available in the system by the library consumer. The prop to
declare such fonts is
The versatile new list component gives access to 47 markers
for custom CSS Counter
list-style-type CSS property and
start attribute. There is also an experimental RTL feature!
Note that the thai and arabic indic counters have been rendered via @jsamr/counter-style presets, and the russian counter has been rendered with a custom, 2 lines-of-code counter renderer. Learn more about this fancy feature and examples in the dedicated article.
The new internal image renderer is shipped with
object-fit CSS property support.
Moreover, its building blocks are completely reusable for custom
To render the container of the
To render the fallback view on error state.
To render the fallback view on loading state.
To render the image on success state..
To get the state of the image resource fetching.
The three-layer rendering architecture shows its potential when rendering many HTML snippets at a time. It basically means that you can put configuration in a context to avoid the cost of instantiating the TRE too many times:
is equivalent to this (explicit 3 layers):
It also offers the ability to select the root of the document to render, and to inspect the DOM object asynchronously before rendering.
After merging the Foundry PR to master, 73% of open issues have been closed. Most fixes stem from the efficiency and rigor of the new test-driven CSS processor and Transient Render Engine. Most notable areas of fixes:
- Unrecognized styles crashing the app. The new CSS processor is strict and deterministic in what is translatable to React Native styles and what is not.
- Missing inheritable styles. Styles inheritance and specificity are implemented and battle-tested in the TRE.
- List prefixes styles not inheriting from parent styles (color...). The new list internal renderer takes them all.
- Missing HTML tags support. The TRE now has explicit support for all the
tags specified in the HTML5 WHATWG living
standard. However, not all tags will be
rendered. Tags with a content model set to
nonewill not be rendered (you can override this model though). Check-out the list of all tags and their models in the
With all the bug fixes, high test coverage and API stability, entering the
beta stage means the Foundry release is now ready for production. Test coverage for
the CSS processor and TRE is 100% (see
native-html/core) repository. The
react-native-render-html package has a test coverage above 64%, and will
rise to above 90% by the end of the beta stage.
I want to thank Maxime Bertonnier, the original
first contributor of
react-native-render-html for letting me join the team
and take over this awesome project. I want to also thank all those amazing
alpha-testers from the community who have helped me refine the API over the
last 7 months. And finally, kudos to Expensify,
Inc. for hiring me to build the first iteration of the engine, which was
originally motivated by the lack of whitespace collapsing support.