# Structured Text fields

Rich-text in DatoCMS is stored in [Structured Text](https://www.datocms.com/docs/content-modelling/structured-text.md) fields, as it offers many advantages over regular HTML.

There's a lot to be said about Structured Text and the extensibility of it, but for now let's just say that it returns content in a particular [JSON format called `dast`](https://www.datocms.com/docs/structured-text/dast.md) which resembles this example:

```json
{
  "schema": "dast",
  "document": {
    "type": "root",
    "children": [
      {
        "type": "heading",
        "level": 1,
        "children": [
          {
            "type": "span",
            "value": "Hello world!"
          }
        ]
      }
    ]
  }
}
```

To make it easy to render Structured Text inside your React Router projects, we released a package called [`react-datocms`](https://github.com/datocms/react-datocms) that exposes a `<StructuredText />` component that performs all the tedious work for you.

To take advantage of it, install the [`react-datocms`](https://github.com/datocms/react-datocms) package if you haven't already:

Terminal window

```bash
npm i --save react-datocms
```

Then, inside your page, make a [GraphQL query to fetch a Structured Text field](https://www.datocms.com/docs/content-delivery-api/structured-text-fields.md), and feed the result to the `data` prop of a `<StructuredText />` component:

```tsx
import type { Route } from './+types/home';
import { load } from '~/lib/datocms';
import { StructuredText } from 'react-datocms';

const HOMEPAGE_QUERY = `query HomePage($limit: IntType) {
  posts: allBlogPosts(first: $limit) {
    id
    title
    content {
      value
    }
  }
}`;

export async function loader() {
  return load(HOMEPAGE_QUERY, {
    variables: { limit: 10 },
  });
}

export default function Home({ loaderData }: Route.ComponentProps) {
  const { posts } = loaderData;

  return (
    <div>
      {posts.map(blogPost => (
        <article key={blogPost.id}>
          <h6>{blogPost.title}</h6>
          <StructuredText data={blogPost.content} />
        </article>
      ))}
    </div>
  );
}
```

## Rendering special nodes

Other than “regular” formatting nodes — paragraphs, headings, lists, etc. — Structured Text documents can contain four special types of node:

-   [`itemLink` nodes](https://www.datocms.com/docs/structured-text/dast.md#itemLink) are just like regular HTML hyperlinks, but point to other records instead of URLs;
-   [`inlineItem` nodes](https://www.datocms.com/docs/structured-text/dast.md#inlineItem) let you directly embed a reference to a record in-between regular text;
    
-   [`block` nodes](https://www.datocms.com/docs/structured-text/dast.md#block) let you embed a DatoCMS block record in-between regular paragraphs;
-   [`inlineBlock` nodes](https://www.datocms.com/docs/structured-text/dast.md#block) lets you embed a DatoCMS block record in-between regular text;
    

If a Structured Text document contains one of these nodes, then we need to change the GraphQL query, so that we also fetch all the records and blocks it references.

As an example, if the field can link to other `Blog posts`, and can embed blocks of type `Image block` and and `Mention block`, then the query should change like this:

```jsx
const HOMEPAGE_QUERY = `query HomePage($limit: IntType) {
  posts: allBlogPosts(first: $limit) {
    id
    title
    content {
      value
      blocks {
        ... on RecordInterface {
          id
          __typename
        }
        ... on ImageBlockRecord {
          image { url alt }
        }
      }
      inlineBlocks {
        ... on RecordInterface {
          id
          __typename
        }
        ... on MentionBlockRecord {
          username
        }
      }
      links {
        ... on RecordInterface {
          id
          __typename
        }
        ... on BlogPostRecord {
          slug
          title
        }
      }
    }
  }
}`;
```

We also need to tell `<StructuredText />` how you want such nodes to be rendered:

```jsx
return (
  <StructuredText
    data={blogPost.content}
    renderInlineRecord={({ record }) => {
      switch (record.__typename) {
        case "BlogPostRecord":
          return <a href={`/blog/${record.slug}`}>{record.title}</a>;
        default:
          return null;
      }
    }}
    renderLinkToRecord={({ record, children }) => {
      switch (record.__typename) {
        case "BlogPostRecord":
          return <a href={`/blog/${record.slug}`}>{children}</a>;
        default:
          return null;
      }
    }}
    renderBlock={({ record }) => {
      switch (record.__typename) {
        case "ImageBlockRecord":
          return <img src={record.image.url} alt={record.image.alt} />;
        default:
          return null;
      }
    }}
    renderInlineBlock={({ record }) => {
      switch (record.__typename) {
        case "MentionBlockRecord":
          return <code>@{record.username}</code>;
        default:
          return null;
      }
    }}
  />
);
```

## Related content in "React Router"

- [React Router + DatoCMS Overview](https://www.datocms.com/docs/react-router.md)
- [Managing images](https://www.datocms.com/docs/react-router/managing-images.md)
- [Displaying videos](https://www.datocms.com/docs/react-router/displaying-videos.md)
- [Structured Text fields](https://www.datocms.com/docs/react-router/structured-text-fields.md)
- [Adding SEO to pages](https://www.datocms.com/docs/react-router/seo-management.md)
- [Setting up a preview mode](https://www.datocms.com/docs/react-router/setting-up-a-preview-mode.md)
- [Real-time updates](https://www.datocms.com/docs/react-router/real-time-updates.md)