Introduction to Creating and Rendering Pages and Widgets

On a Scrivito website, page and widget classes as well as instances of them are represented as React components. The examples in this guide use ES6 and JSX. All APIs described here are also available with ES5 and without JSX, though.

Page components

Pages are instances of Scrivito object classes that are based on the Obj model class Scrivito provides. For rendering the instances of a page model class, a corresponding component needs to be provided. Take a look at this simple page model as an example:

Copy
import * as Scrivito from 'scrivito';

Scrivito.provideObjClass('BlogPostPage', {
  attributes: {
    title: "string",
    author: "string",
    body: "html",
  }
});

To define a component for such a class, use the Scrivito.provideComponent function, like so:

Copy
import * as React from 'react';
import * as Scrivito from 'scrivito';

Scrivito.provideComponent('BlogPostPage', ({ page }) =>
  <div>
    <h1>{ page.get('title') }</h1>
    <span>By: { page.get('author') }</span>
    <div>{ page.get('body') }</div>
  </div>
);

Page components can also be stateful and use the full React component API. For this, pass a React.Component class to Scrivito.provideComponent. The component will then receive the page to render as props.page.

Widget components

Defining widget components is similar to defining page components:

Copy
import * as Scrivito from 'scrivito';

Scrivito.provideWidgetClass('HeadlineWidget', {
  attributes: {
    headline: "string"
  }
});

Analogous to Obj being the base class of all page classes, Widget is the base class of all widget classes. Again Scrivito.provideComponent is used for creating a component for rendering instances of this HeadlineWidget class:

Copy
import * as React from 'react';
import * as Scrivito from 'scrivito';

Scrivito.provideComponent('HeadlineWidget', ({ widget }) =>
  <h1>{ widget.get('headline') }</h1>;
);

That's all! A HeadlineWidget is now rendered using the markup provided above.

If you want to handle state using React's component API in your widget component, you can pass a React.Component class to Scrivito.provideComponent instead of a functional component. In this case, the widget to render is passed to the component via props.widget. See also Using React Components with Scrivito’s Model Classes.

Making content editable

One thing is still missing from the component examples above: CMS content gets rendered, but the content cannot be edited. In order to enable in-place editing, a special helper component, Scrivito.ContentTag, is available. Let's revise the widget component above and make it editable:

Copy
import * as React from 'react';
import * as Scrivito from 'scrivito';

Scrivito.provideComponent('HeadlineWidget', ({ widget }) =>
  <Scrivito.ContentTag tag="h1" content={ widget } attribute="headline"/>
);

Scrivito.ContentTag expects either a Widget or an Obj instance to be passed in via content, and the name of an attribute to be passed in via attribute.

By default, it renders a div tag, containing a default DOM representation of the content of the given attribute. In the example above, a string type attribute is passed in. The default for a string attribute is to just put the (escaped) string contents into the DOM.

The rendered tag can be customized using the tag property. You can also customize the DOM representation of the attribute by providing child components to <Scrivito.ContentTag>, like so:

Copy
<Scrivito.ContentTag content={ page } attribute="tags">
  { widget.get('tags').map(tag => 
      <span key={ tag }>
        { tag }
      </span> 
  }
</Scrivito.ContentTag>

The result would be something like this:

Copy
<div><span>Tag 1</span><span>Tag 2</span></div>

Rendering widgets

Another important use case of Scrivito.ContentTag is to render widgets from attributes of the widgetlist type:

Copy
<Scrivito.ContentTag content={ myPage } attribute="myWidgetlist" />

In this case, Scrivito simply renders all widgets in the widgetlist using the components that have been registered for them by means of provideComponent.

Rendering images

For convenience, Scrivito offers the Scrivito.ImageTag component for rendering images:

Copy
<Scrivito.ImageTag content={ myImageObj } />

This component basically creates the following markup, which the developer could also write manually, of course:

Copy
<img src={ myImageObj.get('blob').url } />

However, in contrast to the <img> tag provided manually, the ImageTag component optimizes image loading and resizes images dynamically to speed up their delivery.

Using the optional attribute property, you might also pass in an attribute of the reference type. An attribute of this type is typically used in an image widget for pointing to the image object associated with it. This is how one would implement a simple image widget:

Copy
import * as React from 'react';
import * as Scrivito from 'scrivito';

Scrivito.provideWidgetClass('ImageWidget', {
  attributes: {
    image: "reference",
  }
});

Scrivito.provideComponent('ImageWidget', ({ widget }) => 
  <Scrivito.ImageTag content={ widget } attribute=”image” />
);

In summary ...

Pages and widgets are based on object and widget model classes. Object and widget instances are rendered by components provided for these classes. Typically, those components use Scrivito.ContentTag and other helper components built into Scrivito to render page and widget attributes and make them editable.