Was this page helpful?

Building your first app

The demo app we're about to build is called Blog Post Metrics. It will enhance your editorial experience when creating a blog post by providing useful metrics such as word count and a reading time indicator. The metrics will be shown in the entry editor in the sidebar for a given blog post entry.

Sidebar Content Type

Prerequisites

In order to successfully complete this tutorial:

  • You'll need the latest LTS version of Node.js installed on your machine. If you don't have Node.js installed, you can download it here.
  • You should be comfortable using your computer’s command line and text editor.
  • You’ll need to be able to read and write HTML, CSS, and JavaScript.
  • You should be familiar with installing software using the Node package manager.
  • You'll need a free Contentful account and Contentful space. You can sign up here.

What to expect

In this tutorial you'll learn:

  • How to create an app.
  • How to configure where your app is shown in the web app.
  • How to install an app into your space.
  • How to choose which content type your app interacts with.

If you prefer to start tinkering directly, you can clone the example code and go from there.

Table of contents

Tools

We will use several tools and libraries throughout the tutorial. We choose these technologies because we think they provide the best developer experience possible.

React

We use React to render our views for the app and handle our logic. React is a JavaScript library for building user interfaces. However, using React is not mandatory to create apps.

App SDK

The App SDK provides the methods that are necessary to interact with the Contentful web app. We will only use a subset of the methods, but if you want to know the full scope of what is possible, take a look at our SDK reference documentation.

Forma 36

We use Forma 36 to achieve the same look and feel of the Contentful web app. Forma 36 is Contentful's design system.

TypeScript

The app is written in TypeScript. However, you do not need any TypeScript knowledge in order to complete this tutorial. Apps can also be written in JavaScript without losing any of the functionality.

Set up your content model

Create a content type

Before we start, make sure to have a content type set up and an entry we can test the app on. If you are not familiar with the concept of content types, you can read more about content types here. If you already know how to create a content type, you can skip this section.

  1. Go to your content model page.
  2. Click on Add content type.
  3. Enter the name of the content type you’re creating (in this case, “Blog post”) and a short description. Then click Create when satisfied.

Create your content type

If you already have a content type called Blog post, rename the content type as you like. However, for the rest of the tutorial, we will assume that the content type is called Blog post.

Set up your fields

The next step is to define what kind of information should be stored for each blog post. This is done by adding fields. For our Blog post content type, we’ll be using two types of fields:

  • Text
  • Long text

To add fields:

  1. Go to your content model
  2. Click the Add field button and select Text. Give the new field the name of Title and click Create.
  3. Click the Add field button and select Text. Give the new field the name of Body. Select Long text, full-text search and click Create.

Content type long text

When finished adding fields, click Save.

Your content type should look like this:

Content type Blog post

Make sure you name your Long text field Body so it has a field ID called body.

Set up your project

As a first step, you need to create a project directory where you can work in. We will use a tool called create-contentful-app. This tool makes it easy to create apps with React and Forma 36 and offers a modern build setup with no configuration.

npx @contentful/create-contentful-app init my-first-app

After some time our script is ready and initializes our first app. Navigate to the newly created folder and start the app.

cd my-first-app
npm run start

This hosts your application on http://localhost:3000. We'll later connect to this through the Contentful web app

Embed your app in the Contentful web app

In order to you see your app running in the Contentful web app, you need to create an AppDefinition to expose the app to Contentful. An AppDefinition is an entity that represents an app in Contentful and stores general information about it.

Create your AppDefinition

Go the to the management view for your apps. This management view lives under your organization settings since AppDefinitions are bound to your Contentful organization.

Create your `AppDefinition`

If this isn’t your first app, then the Create app button will be in the top-right corner of the Apps page.

Click on Create an app and you will be redirected to a page where you can provide details about your app.

  1. Provide a name for your app. This can be whatever you want, we chose Blog Post Metrics for this tutorial.

  2. Enter an app url. The is the url where our app is running. Since we are running our app locally the url is http://localhost:3000.

  3. Specify the app locations. Since we want to see the metrics for our blog posts in the sidebar of the entry editor, we check the location Entry sidebar. Additionally, we select the location App configuration screen, as we will be using this location at a later stage.

App locations specify where our app can appear in the Contentful web app. For more details, see our app location documentation, which explains the benefits of rendering your app in different locations.

Click on Create app when you are done filling in the details.

Create your AppDefinition

Install your app

After you created your AppDefinition, your app should appear on the app listing page in the list of available apps.

Go to your app listing page

WIP: Private app marketplace

Click on your app and you will be asked to authorize access for your app.

Authorize your app

Confirm the dialog and you will be taken to your config screen of your app.

If you see your config screen that means our app was successfully loaded and embedded in the Contentful web app.

Click the Install button to install your app.

Install your app

Congrats, your app is now installed to your current space and environment! 🎉

Configure your app

The config screen is rendered by the ConfigScreen component. Lets fire up our code editor of choice and open our project that was generated by create-contentful-app. You will find the component under src/components/ConfigScreen.tsx. Any changes you make here will be reflected in the Contentful web app. Let's change our headline from App Config to Blog Post Metrics Config.

Save the file and watch the config screen update in real time.

src/components/ConfigScreen.tsx

Update config screen

Assign your app to a content type

Now that you have installed our app, you can assign it to your content type Blog post that you created earlier.

  1. Go to your content model page and click on the content type Blog post.
  2. Click on the sidebar tab.
  3. Click the + button on the Blog Post Metrics card and the app will be assigned to the sidebar.

Do not forget to click the Save button in the top right corner to save your configuration. You can even change the order in which the sidebar widgets should appear by dragging the cards up and down.

Sidebar Content Type

See your app in action

Go to your content tab and create an entry with the content type Blog post. You should see a sidebar app now in your entry editor.

Sidebar Content Type

Lets open the Sidebar component in our project. All the component does is return a paragraph saying Hello Sidebar Component.

src/components/Sidebar.tsx

import React from 'react';
import { Paragraph } from '@contentful/forma-36-react-components';
import { SidebarExtensionSDK } from '@contentful/app-sdk';

interface SidebarProps {
  sdk: SidebarExtensionSDK;
}

const Sidebar = (props: SidebarProps) => {
  return <Paragraph>Hello Sidebar Component</Paragraph>;
};

export default Sidebar;

All the changes you make here to the component will also be reflected directly in the web app.

Sidebar updates in real time

Calculate the metrics

Let's provide some metrics for the blog post. For calculating the word count and the reading time we will use a library called reading-time. Navigate to your project folder and install the library with:

npm install reading-time

We can use the sdk object, which gets passed into every view, to interact with data in Contentful. The sdk.entry.fields object holds all the fields that are in an entry. We can get an individual field by its fieldId, in this case body as we specified it when creating our content type.

Next we need to store the information about the blog post in state to render the appropriate information. We use the getValue method to retrieve the current value from the field.

src/components/Sidebar.tsx

import React, { useState } from 'react';
import { Paragraph } from '@contentful/forma-36-react-components';
import { SidebarExtensionSDK } from '@contentful/app-sdk';

interface SidebarProps {
  sdk: SidebarExtensionSDK;
}

// The field ID from our blog post field
const CONTENT_FIELD_ID = 'body';

const Sidebar = (props: SidebarProps) => {
  // The sdk allows us to interact with the Contentful web app
  const { sdk } = props;

  // With the field ID we can reference individual fields from an entry
  const contentField = sdk.entry.fields[CONTENT_FIELD_ID];

  // Get the current value from the blog post field and store it in React state
  const [blogText, setBlogText] = useState(contentField.getValue());

  return <Paragraph>Hello Sidebar Component</Paragraph>;
};

export default Sidebar;

If we want to calculate our metrics as soon as somebody starts writing content for the blog post, we need to listen to onChange events from the field. The sdk provides a field API which we can leverage to listen for value changes. We use the method onValueChanged to listen for any content updates and call a method readingTime which will take the value and calculate our desired metrics. It will do all the heavy lifting for us and return an object which holds the word count and the time to read.

The last thing we want to do is display the calculated metrics in our sidebar. For this we import a few Forma 36 components. We will use the List, ListItem and Note component to give our app the look and feel of the Contentful web app. The final code should look like this.

src/components/Sidebar.tsx

import React, { useState, useEffect } from 'react';
import { List, ListItem, Note } from '@contentful/forma-36-react-components';
import { SidebarExtensionSDK } from '@contentful/app-sdk';
import readingTime from 'reading-time';

interface SidebarProps {
  sdk: SidebarExtensionSDK;
}

const CONTENT_FIELD_ID = 'body';

const Sidebar = (props: SidebarProps) => {
  const { sdk } = props;

  const contentField = sdk.entry.fields[CONTENT_FIELD_ID];

  const [blogText, setBlogText] = useState(contentField.getValue());

  // Listen for onChange events and update the value
  useEffect(() => {
    const detach = contentField.onValueChanged((value) => {
      setBlogText(value);
    });
    return () => detach();
  }, [contentField]);

  // Calculate the metrics based on the new value
  const stats = readingTime(blogText || '');

  // Render the metrics with Forma36 components
  return (
    <>
      <Note style={{ marginBottom: '12px' }}>
        Metrics for your blog post:
        <List style={{ marginTop: '12px' }}>
          <ListItem>Word count: {stats.words}</ListItem>
          <ListItem>Reading time: {stats.text}</ListItem>
        </List>
      </Note>
    </>
  );
};

export default Sidebar;

You should see now the app in your sidebar. Type some content in your field and see how the app updates!

Final App

Congrats on building your first app !🎉

You can find the full example code here.

Deployment

In order to deploy your app and make it available to the public internet, you need to create a production build of your app. Our tool create-contentful-app provides a build script. You can run:

npm run build

This will create a build directory with a production build of your app. We are not opinionated on how you deploy your application. There are a variety of services that host static web applications. It is important to note that once you have deployed your application, you need to update your AppDefinition to refer to your deployment.

Additional Ressources