Magnolia React Editor

This page describes the installation, components and functions of the Magnolia React Editor — a lightweight, fully-featured library connecting React projects with the WYSIWYG authoring experience of the Magnolia Pages app.

Installation

To install the editor, open the command prompt and enter the following command.

npm install @magnolia/react-editor
react editor is the latest version of the Magnolia React Editor.

Reference

<EditableArea>

The wrapping component for areas.

The component can be used only inside the React components that are instantiated by EditablePage. That is, the React component must be in the componentMappings object supplied to the EditablePage via its config parameter.

By default, the area component loops over all of its children components.

EditableArea renders React components for each component node in its content. It determines which component to render based on the mgnl:template value of the node and the componentMappings supplied to the EditablePage config property. The properties of each component and areas (if any) are passed as props to the child components.

The default behavior can be changed with customView.

In the editor view of the Magnolia Pages app, it will add the annotations that are required to render the green bars with the authoring UI. The annotations are added as HTML comments.

Properties

Property Description

content

Area content that is passed as a property to the parent component where the EditableArea is used.

Example
import React from 'react';
import { EditableArea } from '@magnolia/react-editor';

function Home(props) {
  // main is area name as defined in page/component YAML definition
  const { main } = props;

  return (
    <>
      {main && <EditableArea content={main} />}
    </>
  );
}

export default Home;

parentTemplateId

Required only when using templateDefinitions.

import React from 'react';
import { EditableArea } from '@magnolia/react-editor';

function Home(props) {
  // main is area name as defined in page/component YAML definition
  // metadata is set of extra component informations added by react-editor
  const { main, metadata } = props;

  return (
    <>
      {main && <EditableArea content={main} parentTemplateId={metadata['mgnl:template']} />}
    </>
  );
}

export default Home;

elementType

EditableArea wraps its children components in a single div element. The wrapping element can be changed by passing a new element type with elementType, which must be a valid DOM element passed as string.

Example
<EditableArea content={main} />
/*
<div>
  ...children
</div>
*/

<EditableArea content={main} elementType='ul' />
/*
<ul>
  ...children
</ul>
*/

className

Used to add CSS classes to EditableArea wrapping element.

<EditableArea content={main} className='foo' />
/*
<div class="foo">
  ...children
</div>
*/

customView

Function to overwrite the default behavior of the EditableArea.

customView receives one variable with all area data passed as the content property.

import React from 'react';
import { EditableArea, EditableComponent } from '@magnolia/react-editor';

function myCustomView({ content }) {
  return (
    <>
      {content['@nodes'].map((nodeName) => (
        <EditableComponent key={content[nodeName]['@id']} content={content[nodeName]} />
      ))}
    </>
  );
}

function Home(props) {
  // main is area name as defined in page/component YAML definition
  const { main } = props;

  return (
    <>
      {main && <EditableArea content={main} customView={myCustomView} />}
    </>
  );
}

export default Home;

<EditableComponent>

The wrapping component for components.

EditableComponent component can only be used inside the customView of the EditableArea.

The component determines which React component to render based on the mgnl:template value of the content and the componentMappings supplied to the EditablePage config property. Component dialog properties and areas are passed to the component as props.

Properties

Property Description

content

Component content that is passed as part of area content.

<EditablePage>

The wrapping component for Magnolia-managed page content.

It determines which React component to render based on the mgnl:template value of the content and the componentMappings supplied to the EditablePage config property. Page dialog properties and areas are passed to the component as props.

In the editor view of the Pages app, it will add the annotations that are required to render the green bars with the authoring UI. The annotations are added as HTML comments.

Properties

Property Description

content

Page content response coming from Magnolia Delivery API.

Example endpoint definition
class: info.magnolia.rest.delivery.jcr.v2.JcrDeliveryEndpointDefinition
workspace: website
limit: 100
systemProperties:
  - mgnl:template
depth: 10
nodeTypes:
  - mgnl:page
childNodeTypes:
  - mgnl:area
  - mgnl:component

An example response can be seen here.

config

Configuration object containing the componentMappings object with mappings between the mgnl:template values and React components.

Example
import Home from './pages/Home';

const config = {
  componentMappings: {
    'spa:pages/Home': Home,
  },
};

templateAnnotations

or

templateDefinitions

Use templateAnnotations. templateDefinitions are deprecated.

Template information required for the Page Editor to create the authoring UI (the green bars).

  • templateAnnotations are fetched from

    <MAGNOLIA_INSTANCE>/.rest/template-annotations/v1/<PAGE_PATH>
    Example
    https://demo.magnolia-cms.com/.rest/template-annotations/v1/travel
  • templateDefinitions are fetched from

    <MAGNOLIA_INSTANCE>/.rest/template-definitions/v1/<PAGE_TEMPLATE>
    Example
    https://demo.magnolia-cms.com/.rest/template-definitions/v1/travel-demo:pages/home

Example

import React from 'react';
import ReactDOM from 'react-dom';
import { EditablePage, EditorContextHelper } from '@magnolia/react-editor';
import Home from './pages/Home';

const config = {
  componentMappings: {
    'spa:pages/Home': Home,
  },
};

class App extends React.Component {
  state = {};

  async componentDidMount() {
    let templateAnnotations;
    const pageRes = await fetch('http://localhost:8080/.rest/pages/spa-home');
    const page = await pageRes.json();

    if (EditorContextHelper.inIframe()) {
      const templateAnnotationsRes = await fetch(
        'http://localhost:8080/.rest/template-annotations/v1/spa-home'
      );

      templateAnnotations = await templateAnnotationsRes.json();
    }


    this.setState({ page, templateAnnotations });
  }

  render() {
    const { page, templateAnnotations } = this.state;

    return (
      <>
        {page && config && <EditablePage content={page} config={config} templateAnnotations={templateAnnotations} />}
      </>
    );
  }
}

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

EditorContextHelper.inIframe

A function that returns true when run in the IFRAME app or when global.mgnlInPageEditor is set to true.

Alternatively, you can check the URL of the requested website. In the Pages app, Magnolia adds the mgnlPreview parameter to the IFRAME preview source.

Example
import { EditorContextHelper } from '@magnolia/react-editor';

if (EditorContextHelper.inIframe()) {
  // ...
}

// Alternative approach
if (window.location.search.includes('mgnlPreview')) {
  // ...
}

Demo

For headless SPA demos showcasing the Magnolia React Editor, see minimal-headless-spa-demos.

Changelog

A list of notable changes for any given version is available on the changelog page.

Feedback

Headless