Add Contentful to your TypeScript project

How to

Software development

Written by

Dan Haws

Date

2 years ago

Read time

7 minutes

Businesses often use content management systems (CMSs) to update content without requiring developer skills. These systems come in two main forms: traditional CMSs (where styling and data are interlinked) and headless CMSs (where data is separated from the styling).

If you're struggling to decide on a content management system that works for your business, Contentful could be a great option for you. At Contic, our developers are experts in software development and implementing CMSs. If you're interested in learning more about Contic or would like our help in getting your product to market faster, feel free to contact us through our website's contact page.

This blog will discuss the use of the headless CMS Contentful.

Why use a headless CMS?

Headless CMSs are a powerful tool for managing website content. They generate data that can be accessed via an API, enabling you to update content across multiple platforms instantly. This means that you can update content on a mobile application and a website at the same time without having to modify any code.

One of the biggest advantages of headless CMSs is their flexibility. Content is distributed through an API, which allows developers to use any frontend tools they desire and format content in any way they like. This makes headless CMSs a great choice for more advanced frontends that take advantage of AI, A/B testing, animations, or user tracking.

Unlike traditional CMSs, headless CMSs offer unlimited styling options that aren't limited to any specific templates or designs. This makes it easier to create more customised and unique user experiences.

Using a headless CMS instead of a traditional CMS like Square Space can provide significant benefits for your organisation. By allowing the use of any frontend tools in your project, it provides greater control over the performance, accessibility, and SEO scores of your web application. Good SEO scores are crucial for achieving high rankings in search engines. Poor SEO scores can significantly reduce the amount of traffic your web app receives, thereby affecting the overall success of your organisation.

Setup

Firstly you should set up a Contentful account and a space for your project.

After doing this you’re going to need to add your dependencies to your code base:

yarn add Contentful // and if you're planning on using rich text. yarn add @contentful/rich-text-react-renderer

After doing this you will need to create a Contentful client.

You can get your space ID and access token used in the client creation from within settings under API keys on Contentful.

contentful

After getting these two keys, you can create your client.

/utils/contentfulClient import * as Contentful from 'contentful'; const accessToken = process.env.SECRET_ACCESS_TOKEN_CONTENTFUL || ''; const space = process.env.SECRET_SPACE_CONTENTFUL || ''; export const contentfulClient = () => { if (accessToken !== '') { const client = Contentful.createClient({ accessToken, space, }); return client; } return null; };

Content models

Understanding content models is fundamental to creating intuitive and insightful designs. Since the structuring of your data dictates how you can use it. For the sake of conciseness, I am only going to focus on the example of creating a blog hub.

Content types

Inside the content model, you can create content types which are a collection of fields that can be queried once you’ve created some content later. This can either be done as a collection of entries or as a specific entry. There are options for name, the API identifier (this is what you are going to be using to query your selected content) and a description.

contentful 2

Fields

Nine data types can be chosen from, which can be seen below. This is fairly self-explanatory, but you should create a new field for every piece of content that you want to be editable from Contentful.

field contentful

The specific field I am going to show you in this example is a text field for a slug which can be used for dynamic routing. After selecting the short text field type in a name, field ID and then press ‘create and configure’.

contentful 3

Configuring

Validation

When you create a field you can apply requirements for the field. In the below example, I have set the slug as a required field, and selected that it must be unique. Regular expressions have also been used in this example to ensure that the slug is of a valid format.

contentful slug

Appearance

Appearances are used to determine what is shown to the client when they create content. As well as help text which can be used to create a more consumer-friendly experience. In the example below we have selected generated slug, which automatically creates a slug (that can still be edited) based on the main text of the blog.

slug symbol

Completed content model

Now you’re at the stage where you have created you first content model with all the fields you want. ‘here’s one I made earlier’. Note the content type ID as this what you are going to use to fetch this data.

Screenshot 2023-02-15 at 12.27.59

Getting the data

Within your uppermost page file, use the Contentful client that you created earlier. Then pass your content into your page using getStaticProps. There are several ways to query your data, but for this example we are querying the content type, ‘blog’ to get all the entries of that type.

//pages/Blogs.tsx import { Blogs } from '@/components/pages'; import { contentfulClient } from '@/utils/contentfulClient'; import type { GetServerSideProps } from 'next'; const client = contentfulClient(); export const getStaticProps: GetStaticProps = async () => { const response = await client.getEntries({ content_type: 'blog' }); return { props: { data: response } }; }; const BlogsPage = Blogs; export default BlogsPage;

If you are using typescript you then need to determine the types of your data. These are the types for the above content model.

//utils/contentfulDataTypes.ts import * as Contentful from 'contentful'; import * as CFRichTextTypes from '@contentful/rich-text-types'; export interface TypeBlogPostFields { description: Contentful.EntryFields.Symbol; name: Contentful.EntryFields.Symbol; image: Contentful.Asset; blogContent: CFRichTextTypes.Document; slug: Contentful.EntryFields.Symbol; thumbnail: Contentful.Asset; }

After completing the above step you can pass through your data to the page, and style it how you would any queryable data.

//src/components/pages/Blogs.tsx import { TypeBlogPostFields } from '@/utils/contentfulDataTypes'; import { ContentfulCollection, Entry } from 'contentful'; import Link from 'next/link'; import React from 'react'; export const Blogs = ({ data, }: { data: Partial<ContentfulCollection<Entry<TypeBlogPostFields>>>; }) => { const { items } = data; return ( <div className="flex flex-col align-center"> <div className=""> <h2 className=""> From the blog </h2> <p className="">Blogs!</p> <div className=""> {items?.map((item) => ( <Link href={`/blogs/${item.fields.slug}`} key={item.fields.slug}> <div className=""> <div className=""> <img className="" src={item.fields.thumbnail.fields.file.url} alt={item.fields.thumbnail.fields.file.url} /> </div> <div className=""> <p className="">{item.fields.name}</p> <p className="">{item.fields.description}</p> </div> </div> </Link> ))} </div> </div> </div> ); };

There it is, you have successfully managed to implement Contentful into your Project. You could stop here, or continue reading to see how you can use Rich text to allow for your client to have more control over the formatting of their content.

Rich text

Only using text, numbers, specific files, etc… can be fairly limiting for clients as it does not allow for much changes in terms of page layout since you are passing your data directly into styled components. One way to allow for more customisation is through the use of rich text.

You create a field in the same way as previously but instead select the rich text field type. Name your rich text field and select ‘create and configure’.

Screenshot 2023-02-16 at 10.55.33

You can then choose the formatting options that you want to be used. For simplicities sake, I have selected h1, h2, links, bold, italics and underlined. You pass through this data as you would for any type, but you need to style it slightly differently.

Screenshot 2023-02-16 at 10.59.18

Styling rich text

After querying your data to your page/component you need to use the Contentful package added at the start of this blog (contentful/rich-text-react-renderer). You pass the rich text field into the ‘documentToReactComponents’ as the first argument.

import React from 'react'; import { documentToReactComponents } from '@contentful/rich-text-react-renderer'; import { richTextBlogStyles } from '@/utils/richTextStyles'; import { TypeBlogPostFields } from '@/utils/contentfulDataTypes'; import { Entry } from 'contentful'; export const Blog = ({ data }: { data: Partial<Entry<TypeBlogPostFields>> }) => { return ( <div className="flex flex-col items-center justify-center p-6"> {data.fields?.blogContent && documentToReactComponents(data.fields?.blogContent, richTextBlogStyles) </div> ); };

The second argument you pass into ‘documentToReactComponents’ is the styling options for your richText for each of the types that you have allowed within the formatting options. Here we have done some simple tailwind styling for paragraphs, heading 1 and heading 2.

//utils/contentfulRichTextTypes.ts import { BLOCKS } from '@contentful/rich-text-types'; export const richTextBlogStyles = { renderNode: { [BLOCKS.PARAGRAPH]: ( node: object, children: | string | number | boolean | React.ReactFragment | React.ReactPortal | React.ReactElement | null | undefined ) => { return <p className="text-md font-bold text-black">{children}</p>; }, [BLOCKS.HEADING_1]: ( node: object, children: | string | number | boolean | React.ReactFragment | React.ReactPortal | React.ReactElement | null | undefined ) => { return ( <h1 className="text-2xl font-bold text-black"> {children} </h1> ); }, [BLOCKS.HEADING_2]: ( node: object, children: | string | number | boolean | React.ReactFragment | React.ReactPortal | React.ReactElement | null | undefined ) => { return ( <h2 className="text-xl text-black font-bold"> {children} </h2> ); }, }, };

Conclusion

Congratulations! You have successfully set up Contentful for your TypeScript project.

In conclusion, Contentful can be a valuable tool for clients who want the ability to edit and add content after a project's completion without relying on external developer expertise. The use of rich text fields allows for a high degree of customisation in the available layouts and styling of a given page.

Contentful is relatively easy to set up, and there are many optional plugins available on the Contentful website. So why not consider using it for your future projects?

person with an email icon

Subscribe to our newsletter

Be the first to know about our latest updates, industry trends, and expert insights

Your may unsubscribe from these communications at any time. For information please review our privacy policy.