# Structured text `` is a React component that you can use to render the value contained inside a DatoCMS [Structured Text field type](https://www.datocms.com/docs/structured-text/dast). ## Table of Contents - [Installation](#installation) - [Basic usage](#basic-usage) - [Custom renderers for inline records, blocks, and links](#custom-renderers-for-inline-records-blocks-and-links) - [Override default rendering of nodes](#override-default-rendering-of-nodes) - [Props](#props) ## Installation ``` npm install --save react-datocms ``` ## Basic usage ```js import React from 'react'; import { StructuredText } from 'react-datocms'; const Page = ({ data }) => { // data.blogPost.content = { // value: { // schema: "dast", // document: { // type: "root", // children: [ // { // type: "heading", // level: 1, // children: [ // { // type: "span", // value: "Hello ", // }, // { // type: "span", // marks: ["strong"], // value: "world!", // }, // ], // }, // ], // }, // }, // } return (

{data.blogPost.title}

{/* ->

Hello world!

*/}
); }; const query = gql` query { blogPost { title content { value } } } `; export default withQuery(query)(Page); ``` ## Custom renderers for inline records, blocks, and links You can also pass custom renderers for special nodes (inline records, record links and blocks) as an optional parameter like so: ```js import React from 'react'; import { StructuredText, Image } from 'react-datocms'; const Page = ({ data }) => { // data.blogPost.content -> // { // value: { // schema: "dast", // document: { // type: "root", // children: [ // { // type: "heading", // level: 1, // children: [ // { type: "span", value: "Welcome onboard " }, // { type: "inlineItem", item: "324321" }, // ], // }, // { // type: "paragraph", // children: [ // { type: "span", value: "So happy to have " }, // { // type: "itemLink", // item: "324321", // children: [ // { // type: "span", // marks: ["strong"], // value: "this awesome humang being", // }, // ] // }, // { type: "span", value: " in our team! We call him " }, // { type: "inlineBlock", item: "1984560" } // ] // }, // { type: "block", item: "1984559" } // ], // }, // }, // links: [ // { // id: "324321", // __typename: "TeamMemberRecord", // firstName: "Mark", // slug: "mark-smith", // }, // ], // blocks: [ // { // id: "1984559", // __typename: "CtaRecord", // title: "Call to action", // url: "https://google.com" // }, // ], // inlineBlocks: [ // { // id: "1984560", // __typename: "MentionRecord", // username: "steffoz", // }, // ], // } return (

{data.blogPost.title}

{ switch (record.__typename) { case 'TeamMemberRecord': return {record.firstName}; default: return null; } }} renderLinkToRecord={({ record, children, transformedMeta }) => { switch (record.__typename) { case 'TeamMemberRecord': return ( {children} ); default: return null; } }} renderBlock={({ record }) => { switch (record.__typename) { case 'CtaRecord': return ( {record.title} ); default: return null; } }} renderInlineBlock={({ record }) => { switch (record.__typename) { case 'MentionRecord': return ( @{record.username} ); default: return null; } }} /> {/* Final result:

Welcome onboard Mark

So happy to have this awesome humang being in our team! We call him @steffoz

Our team at work */}
); }; const query = gql` query { blogPost { title content { value links { ... on RecordInterface { id __typename } ... on TeamMemberRecord { firstName slug } } blocks { ... on RecordInterface { id __typename } ... on CtaRecord { title url } } inlineBlocks { ... on RecordInterface { id __typename } ... on MentionRecord { username } } } } } `; export default withQuery(query)(Page); ``` ## Override default rendering of nodes This component automatically renders all nodes (except for `inlineItem`, `itemLink`, `block` and `inlineBlock`) using a set of default rules, but you might want to customize those. For example: For example: - For `heading` nodes, you might want to add an anchor; - For `code` nodes, you might want to use a custom sytax highlighting component like [`prism-react-renderer`](https://github.com/FormidableLabs/prism-react-renderer); - Apply different logic/formatting to a node based on what its parent node is (using the `ancestors` parameter) - For all possible node types, refer to the [list of typeguard functions defined in the main `structured-text` package](https://github.com/datocms/structured-text/tree/main/packages/utils#typescript-type-guards). The [DAST format documentation](https://www.datocms.com/docs/structured-text/dast) has additional details. In this case, you can easily override default rendering rules with the `customNodeRules` and `customMarkRules` props. ```jsx import { renderNodeRule, renderMarkRule, StructuredText } from 'react-datocms'; import { isHeading, isCode } from 'datocms-structured-text-utils'; import { render as toPlainText } from 'datocms-structured-text-to-plain-text'; import SyntaxHighlight from 'components/SyntaxHighlight'; { const HeadingTag = `h${node.level}`; const anchor = toPlainText(node) .toLowerCase() .replace(/ /g, '-') .replace(/[^\w-]+/g, ''); return ( {children} ); }), // Use a custom syntax highlighter component for code blocks renderNodeRule(isCode, ({ node, key }) => { return ( ); }), // Apply different formatting to top-level paragraphs renderNodeRule( isParagraph, ({ adapter: { renderNode }, node, children, key, ancestors }) => { if (isRoot(ancestors[0])) { // If this paragraph node is a top-level one, give it a special class return renderNode( 'p', { key, className: 'top-level-paragraph-container-example' }, children, ); } else { // Proceed with default paragraph rendering... // return renderNode('p', { key }, children); // Or even completely remove the paragraph and directly render the inner children: return {children}; } }, ), ]} customMarkRules={[ // convert "strong" marks into tags renderMarkRule('strong', ({ mark, children, key }) => { return {children}; }), ]} />; ``` Note: if you override the rules for `inlineItem`, `itemLink`, `block` or `inlineBlock` nodes, then the `renderInlineRecord`, `renderLinkToRecord`, `renderBlock` and `renderInlineBlock` props won't be considered! ## Props | prop | type | required | description | default | | ------------------ | --------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | data | `StructuredTextGraphQlResponse \| DastNode` | :white_check_mark: | The actual [field value](https://www.datocms.com/docs/structured-text/dast) you get from DatoCMS | | | renderInlineRecord | `({ record }) => ReactElement \| null` | Only required if document contains `inlineItem` nodes | Convert an `inlineItem` DAST node into React | `[]` | | renderLinkToRecord | `({ record, children }) => ReactElement \| null` | Only required if document contains `itemLink` nodes | Convert an `itemLink` DAST node into React | `null` | | renderBlock | `({ record }) => ReactElement \| null` | Only required if document contains `block` nodes | Convert a `block` DAST node into React | `null` | | renderInlineBlock | `({ record }) => ReactElement \| null` | Only required if document contains `inlineBlock` nodes | Convert an `inlineBlock` DAST node into React | `null` | | metaTransformer | `({ node, meta }) => Object \| null` | :x: | Transform `link` and `itemLink` meta property into HTML props | [See function](https://github.com/datocms/structured-text/blob/main/packages/generic-html-renderer/src/index.ts#L61) | | customNodeRules | `Array` | :x: | Customize how nodes are converted in JSX (use `renderNodeRule()` to generate rules) | `null` | | customMarkRules | `Array` | :x: | Customize how marks are converted in JSX (use `renderMarkRule()` to generate rules) | `null` | | renderText | `(text: string, key: string) => ReactElement \| string \| null` | :x: | Convert a simple string text into React | `(text) => text` |