---
title: Enriching rich text with inline components (DatoCMS + React)
description: >-
  With inline components we have a new tool to bring designers' imaginations to
  live. Here’s how we use DatoCMS structured text in combination with React.
language: English
url: >-
  https://www.voorhoede.nl/en/blog/enriching-rich-text-with-inline-components-datocms-react/
---

Blog

# Enriching rich text with inline components (DatoCMS + React)

By [Jasper](/en/team/jasper.md)

19 November 2021

## Categories

* [Headless CMS](/en/blog/tag/headless-cms.md)

- [The design challenge](#the-design-challenge)
- [The CMS solution](#-the-cms-solution)
- [The front-end code solution](#-the-front-end-code-solution)

Designers challenge us to come up with technical solutions to build their creations. With inline components we have a new tool to bring their imaginations to live. Here’s how we use DatoCMS structured text in combination with React.

## The design challenge

A design agency recently challenged us with a nifty design for a new website. The design included a section with text and an image side-by-side. Normally this would be a straightforward section to build and create a content model for. However the text contains headings with inline icons and an external link that looks like a button at the end of a paragraph:

![Example of design with inline icon component](https://www.datocms-assets.com/6524/1637333856-p5micvvo.jpeg)

So how do we enable content editors to craft this text with inline elements and how can we render all of this in the UI?

## The CMS solution

Up until recently this challenge would have probably required us to model a form in the CMS where editors needed to construct this section with separate fields for each element. But now more and more [(Headless) CMS’es](https://www.voorhoede.nl/en/services/headless-cms.md) have given super powers to rich text fields, allowing content editors to add custom elements directly inline:

[Structured text with inline records in DatoCMS](https://vimeo.com/641535920)

This new grade of rich text is popularised by Sanity ([portable text](https://www.sanity.io/docs/block-content)), now also available in other CMS’es like Contentful ([rich text with embeds](https://www.contentful.com/developers/docs/concepts/rich-text/)) and in this case using [DatoCMS structured text](https://www.datocms.com/docs/content-modelling/structured-text). We configure our section text to allow inline “External Link” and “Icon” records:

![Screenshots of settings in Dato CMS](https://www.datocms-assets.com/6524/1637334019-thsufowq.jpeg)

## The front-end code solution

We can now query the DatoCMS GraphQL API to obtain the rich text including the inlined components:

```
# components/TextImageSection/TextImageSection.fragment.graphql
fragment textImageSectionFragment on TextImageSectionRecord {
  text {
    value
    links {
      ... on ExternalLinkRecord { _modelApiKey, id, title, url }
      ... on IconRecord { _modelApiKey, id, name, alignment }
    }
  }
  image { ... }
}
```

The result is a large blob of JSON representing the the rich text and all linked records. Luckily DatoCMS also provides a [`react-datocms package`](https://github.com/datocms/react-datocms#structured-text) to easily render this. We configure the provided `<StructuredText>` component to render the inline records with our own custom `<Icon>` and `<ExternalLink>`:

```
// components/TextImageSection/TextImageSection.jsx
import { Image, StructuredText } from 'react-datocms'
import { Icon, ExternalLink } from './elsewhere'

/**
 * @param {import('../../lib/dato').TextImageSectionRecord} props 
 */
export default function TextImageSection({ id, text, image }) {
  return (
    <section>
      <StructuredText
        data={ text }
        renderInlineRecord={ InlineRecord }
      />
      <DatoImage data={ image.responsiveImage } />
    </section>
  )
}

function InlineRecord ({ record }) {
  switch (record._modelApiKey) {
    case 'icon':
      return (
        <Icon
          name={ record.name }
          class={ `icon--${record.alignment}` }
        />
      )
    case 'external_link':
      return (
        <ExternalLink
          title={ record.title }
          url={ record.url }
          class={ 'external-link' }
        />
      )
    default:
      console.warn(`No inline record specified for "${ record._modelApiKey }"`)
      return null
  }
}
```

The result, rich text with inline components ([view live on website](https://sterreschans.nl/contact/#section-64182282)):

![Example of design with inline icon component](https://www.datocms-assets.com/6524/1637333856-p5micvvo.jpeg)

Enjoy the enhanced content experience!

ps. noticed the use of GraphQL fragments and content types in our code? You can read all about it in our blog posts [Componentize data with GraphQL fragments](https://www.voorhoede.nl/en/blog/componentize-data-with-graphql-fragments.md) and [CMS-driven IntelliSense in your code editor](https://www.voorhoede.nl/en/blog/cms-driven-intellisense-in-your-code-editor.md).

## Related blog posts

* ### [Dropbox Paper as a headless CMS](/en/blog/dropbox-paper-as-a-headless-cms.md)
  25 Jan 2019

  By Jasper
* ### [Figma as a CMS; where design and development collide](/en/blog/figma-as-a-cms-where-design-and-development-collide.md)
  10 Feb 2022

  By Bas , Friso
* ### [Safe and convenient CMS migrations with scripted migrations and sandbox environments](/en/blog/scripted-cms-migrations.md)
  25 Nov 2022

  By Frank

[← All blog posts](/en/blog.md)

[Return to top](#top)
