Macros
Contents
Rich Text also supports custom components - aka Macros
.
Background
In order to support more complex structure within Enonic’s Rich Text editor, you can define macros.
Details on defining macros can be found in the XP documentation. |
Default macro handling
The sample content contains an example macro called Factbox
, which has been added to the Lea Seydoux bio.
By default, the RichText component will simply render a fallback placeholder:

To improve the situation, start by implementing a FactBox component.
The FactBox component
Add the following files to your project:
import styles from './FactBox.module.css';
declare type FactBoxProps = {
config: Record<string, any>
children: React.ReactNode
};
export const FactBox = ({config, children}: FactBoxProps) => (<>
<ins className={styles.factbox}>
<strong className={styles.header}>{config.header?.length ? config.header : 'Fact Box'}</strong>
<br/>
{children}
</ins>
</>)
The optional body of a macro is available as a React component called children . |
.icon {
speak: none;
font-style: normal;
font-weight: normal;
font-variant: normal;
text-transform: none;
line-height: 1;
/* Better Font Rendering =========== */
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.factbox {
background-color: rgb(235, 249, 249);
display: block;
text-decoration: none;
-webkit-border-radius: 2px;
-moz-border-radius: 2px;
border-radius: 2px;
clear: both;
-webkit-box-shadow: 0 2px 3px rgba(0, 0, 0, .3);
-moz-box-shadow: 0 2px 3px rgba(0, 0, 0, .3);
box-shadow: 0 2px 3px rgba(0, 0, 0, .3);
min-height: 24px;
line-height: 24px;
font-family: sans-serif;
font-size: 14px;
color: #333;
padding: 10px 20px 10px 44px;
width: 75%;
margin: 20px auto;
position: relative;
}
.factbox .header {
font-size: 14px;
font-weight: bold;
line-height: 24px;
margin: 0;
color: #1f71a1;
}
.factbox .body ul {
padding-left: 0;
}
.factbox .body ul li {
margin: 5px 0;
}
@media screen and (max-width: 720px) {
.factbox {
width: 90%;
}
}
Like other components, you may also declare a query for your Macro - but in this case we already have everything we need in the data returned from the original bio
query.
The Macro component
We now have a FactBox component, but we still need to map it to the Enonic macro definition. This can be solved by implementing a generic Macro component where you map specific macro descriptors to corresponding macro components.
import type {MacroComponent} from '@enonic/react-components';
import {FactBox} from './FactBox';
export const Macro: MacroComponent = ({
config,
descriptor,
children,
...rest
}) => {
if (descriptor === 'com.enonic.app.intro:factbox') {
const props = {...rest, config};
return <FactBox {...props}>{children}</FactBox>;
}
throw new Error(`Macro not found: ${descriptor}`);
}
This component takes care of mapping each macro to its corresponding React component. In our case, FactBox
component implements the macro called com.enonic.app.intro:factbox
in Enonic.
It will throw an error otherwise, which will cause the RichText component’s ErrorBoundary
to render an Error placeholder
.
Use in RichText
Just like with Link
and Image
components, import Macro
component and pass it to the RichText
component:
import {Macro} from './Macro';
// ..
<RichText
// ...
Macro={Macro}
// ...
/>
If you did everything correctly, you should now see the FactBox
macro rendered inside the biography on the Lea Seydoux page:

A final tip
Make an interface for RestProps so you can use it in other components as needed:
export interface RestProps {
personID: string;
}
You may pass additional parameters, such as personID
to the RichText component by supplying a generic interface which declares them:
import { RestProps } from './RestProps';
...
<RichText<RestProps>
...
personID="paramValue"
...
/>
interface RestProps {
personID: string;
}
Import the interface and supply it to the Link.tsx, Image.tsx and Maxro.tsx components to make them aware of the new personID field:
import { RestProps } from './RestProps';
export const Link: LinkComponent<RestProps> = ({
Next steps
Congratulations on completing this tutorial!
For more details on our React Components library, visit the NPM documentation.
To learn more about Enonic’s CMS capabilities, we recommend the Developer 101 tutorial.
To dive deeper into React and building sites with Enonic, have a look at our Next.js integration.