[{"data":1,"prerenderedAt":272},["ShallowReactive",2],{"DefaultLayouten":3,"language-blog-slug-enriching-rich-text-with-inline-components-datocms-react-i18n-slugs":134,"language-blog-slug-en-enriching-rich-text-with-inline-components-datocms-react":138},{"app":4,"menu":31,"footer":66},{"githubUrl":5,"youtubeUrl":6,"linkedinUrl":7,"phoneNumber":8,"emailAddress":9,"legal":10,"addresses":20},"https:\u002F\u002Fgithub.com\u002Fvoorhoede\u002F","https:\u002F\u002Fwww.youtube.com\u002Fchannel\u002FUCzHuhQVYFRixtQN2-swcuGg","https:\u002F\u002Fwww.linkedin.com\u002Fcompany\u002Fde-voorhoede","+31 20 2610 954","post@voorhoede.nl",[11,14,17],{"title":12,"value":13},"KvK","56017235",{"title":15,"value":16},"BTW","NL851944620B01",{"title":18,"value":19},"IBAN","NL14TRIO0320142078",[21,26],{"address":22,"city":23,"googleMapsLink":24,"postalCode":25},"Koivistokade 70","Amsterdam","https:\u002F\u002Fwww.google.com\u002Fmaps\u002Fplace\u002FDe+Voorhoede+%7C+Front-end+Development\u002F@52.396847,4.8700823,17z\u002Fdata=!3m1!4b1!4m5!3m4!1s0x47c5e21d502d2d59:0xbf570944a96ebf45!8m2!3d52.347647!4d4.8502154","1013 BB",{"address":27,"city":28,"googleMapsLink":29,"postalCode":30},"Koornmarkt 22","Delft","https:\u002F\u002Fwww.google.nl\u002Fmaps\u002Fplace\u002FKoornmarkt+22,+2611+EG+Delft\u002F@52.0093477,4.3573054,17z\u002F","2611 EG",{"title":32,"callToActions":33,"links":39},"Site Menu",[34],{"id":35,"title":36,"link":37},"163140902","Contact",{"__typename":38},"ContactRecord",[40,46,51,56,61],{"id":41,"title":42,"link":43},"163140904","Impact",{"__typename":44,"slug":45},"PageRecord","impact",{"id":47,"title":48,"link":49},"163140905","Services",{"__typename":50},"ServiceOverviewRecord",{"id":52,"title":53,"link":54},"163140906","Cases",{"__typename":55},"CaseOverviewRecord",{"id":57,"title":58,"link":59},"163140908","About us",{"__typename":44,"slug":60},"about-us",{"id":62,"title":63,"link":64},"d6WdFJq2SOuc3dWtpibbXQ","Work at",{"__typename":44,"slug":65},"work-at",{"links":67,"copyrightTitle":93,"copyrightLabel":94,"copyrightLink":95,"privacyTitle":96,"privacyLabel":97,"privacyLink":98,"certificatesGrid":99},[68,71,74,77,82,85,88],{"id":69,"title":42,"link":70},"144185264",{"__typename":44,"slug":45},{"id":72,"title":48,"link":73},"144185265",{"__typename":50},{"id":75,"title":53,"link":76},"144185266",{"__typename":55},{"id":78,"title":79,"link":80},"144185267","Blog",{"__typename":81},"BlogPostOverviewRecord",{"id":83,"title":58,"link":84},"144185268",{"__typename":44,"slug":60},{"id":86,"title":36,"link":87},"144185269",{"__typename":38},{"id":89,"title":90,"link":91},"144185270","FAQ",{"__typename":44,"slug":92},"faq","Creative Commons licence and disclaimer","CC BY 4.0","https:\u002F\u002Fcreativecommons.org\u002Flicenses\u002Fby\u002F4.0\u002F","De Voorhoede privacy statement (pdf)","Privacy statement","https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1763455455-vh-isms-006-privacy-statement-de-voorhoede-en.pdf",[100,112,123],{"id":101,"image":102,"link":107},"Xq4bBfg_TZ6Fkjax9mkbLQ",{"url":103,"alt":104,"width":105,"height":106},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353463-b-corp-logo-black-rgb.png","B Corp logo",404,680,{"__typename":108,"id":109,"title":110,"url":111},"ExternalLinkRecord","fGW1ak8XQYaYDLkBSyncog","B Corp","https:\u002F\u002Fwww.bcorporation.net\u002Fen-us\u002Ffind-a-b-corp\u002Fcompany\u002Fde-voorhoede\u002F",{"id":113,"image":114,"link":119},"c5mCXRTiSraRIB25fw1p7Q",{"url":115,"alt":116,"width":117,"height":118},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1687353461-dda-boxlogo-black.png","Dutch Digital Agencies logo",627,480,{"__typename":108,"id":120,"title":121,"url":122},"P6Jh7B0cTv2cKyNEeKVWVQ","Dutch Digital Agencies","https:\u002F\u002Fdutchdigitalagencies.com\u002Fleden\u002Fde-voorhoede\u002F",{"id":124,"image":125,"link":129},"MT5SCyNxSTSr_v5eeATMZw",{"url":126,"alt":127,"width":128,"height":128},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1775730283-dnv.png","DNV logo",518,{"id":130,"title":131,"link":132},"BRtNB5HnT5i-7HkA8IYzBw","DIV",{"__typename":44,"slug":133},"impact\u002Fdigitale-producten-privacy-by-design",[135],{"locale":136,"value":137},"en","enriching-rich-text-with-inline-components-datocms-react",{"page":139},{"slug":137,"i18nSlugs":140,"social":142,"title":143,"subtitle":79,"isArchived":147,"headerIllustration":148,"date":149,"authors":150,"introTitle":159,"items":160,"pivots":229,"relatedBlogPosts":230,"tags":231,"onMountedScript":153,"onUnmountedScript":153},[141],{"locale":136,"value":137},{"title":143,"description":144,"image":145},"Enriching rich text with inline components (DatoCMS + React)","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.",{"url":146},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1637333856-p5micvvo.jpeg",false,null,"2021-11-19T01:00:00.000+01:00",[151],{"name":152,"lastName":153,"slug":154,"image":155},"Jasper","","jasper",{"url":156,"alt":148,"width":157,"height":158},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535518-jasper.jpg",1892,2523,"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.",[161,166,176,179,183,194,197,204,208,213,216,220,223,226],{"__typename":162,"id":163,"title":164,"body":165},"TextSectionRecord","75529613","The design challenge","\u003Cp>\u003Cspan>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:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":168,"image":169,"caption":173,"fullWidth":174,"captionPosition":175},"ImageRecord","75529614",{"url":146,"alt":170,"width":171,"height":172},"Example of design with inline icon component",1600,1088,"Design with inline icon and external link components",true,"bottom",{"__typename":162,"id":177,"title":153,"body":178},"75529615","\u003Cp>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?\u003C\u002Fp>",{"__typename":162,"id":180,"title":181,"body":182},"75529616"," The CMS solution","\u003Cp>\u003Cspan>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 \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fservices\u002Fheadless-cms\u002F\">(Headless) CMS&rsquo;es\u003C\u002Fa>\u003Cspan> have given super powers to rich text fields, allowing content editors to add custom elements directly inline:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":184,"id":185,"mute":174,"loop":174,"autoplay":174,"caption":153,"video":186,"gif":148},"ResponsiveVideoRecord","75529617",{"url":187,"title":188,"height":189,"width":190,"provider":191,"providerUid":192,"thumbnailUrl":193},"https:\u002F\u002Fvimeo.com\u002F641535920","Structured text with inline records in DatoCMS",360,372,"vimeo","641535920","https:\u002F\u002Fi.vimeocdn.com\u002Fvideo\u002F1290514162-5999b7e95c88cad3fe8cfcff2a3e1bd3a6e6cf4fe322cb95a_295x166",{"__typename":162,"id":195,"title":153,"body":196},"75529618","\u003Cp>\u003Cspan>This new grade of rich text is popularised by Sanity (\u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fwww.sanity.io\u002Fdocs\u002Fblock-content\">portable text\u003C\u002Fa>\u003Cspan>), now also available in other CMS&rsquo;es like Contentful (\u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fwww.contentful.com\u002Fdevelopers\u002Fdocs\u002Fconcepts\u002Frich-text\u002F\">rich text with embeds\u003C\u002Fa>\u003Cspan>) and in this case using \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fwww.datocms.com\u002Fdocs\u002Fcontent-modelling\u002Fstructured-text\">DatoCMS structured text\u003C\u002Fa>\u003Cspan>. We configure our section text to allow inline &ldquo;External Link&rdquo; and &ldquo;Icon&rdquo; records:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":167,"id":198,"image":199,"caption":203,"fullWidth":174,"captionPosition":175},"75529619",{"url":200,"alt":201,"width":171,"height":202},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1637334019-thsufowq.jpeg","Screenshots of settings in Dato CMS",663,"Configuring structured text field in DatoCMS",{"__typename":162,"id":205,"title":206,"body":207},"75529620"," The front-end code solution","\u003Cp>We can now query the DatoCMS GraphQL API to obtain the rich text including the inlined components:\u003C\u002Fp>",{"__typename":209,"id":210,"language":211,"body":212},"CodeBlockRecord","75529621","graphql","# components\u002FTextImageSection\u002FTextImageSection.fragment.graphql\nfragment textImageSectionFragment on TextImageSectionRecord {\n  text {\n    value\n    links {\n      ... on ExternalLinkRecord { _modelApiKey, id, title, url }\n      ... on IconRecord { _modelApiKey, id, name, alignment }\n    }\n  }\n  image { ... }\n}",{"__typename":162,"id":214,"title":153,"body":215},"75529622","\u003Cp>\u003Cspan>The result is a large blob of JSON representing the the rich text and all linked records. Luckily DatoCMS also provides a \u003C\u002Fspan>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fdatocms\u002Freact-datocms#structured-text\">\u003Ccode>react-datocms package\u003C\u002Fcode>\u003C\u002Fa>\u003Cspan> to easily render this. We configure the provided \u003C\u002Fspan>\u003Ccode>&lt;StructuredText&gt;\u003C\u002Fcode>\u003Cspan> component to render the inline records with our own custom \u003C\u002Fspan>\u003Ccode>&lt;Icon&gt;\u003C\u002Fcode>\u003Cspan> and \u003C\u002Fspan>\u003Ccode>&lt;ExternalLink&gt;\u003C\u002Fcode>\u003Cspan>:\u003C\u002Fspan>\u003C\u002Fp>",{"__typename":209,"id":217,"language":218,"body":219},"75529623","js","\u002F\u002F components\u002FTextImageSection\u002FTextImageSection.jsx\nimport { Image, StructuredText } from 'react-datocms'\nimport { Icon, ExternalLink } from '.\u002Felsewhere'\n\n\u002F**\n * @param {import('..\u002F..\u002Flib\u002Fdato').TextImageSectionRecord} props \n *\u002F\nexport default function TextImageSection({ id, text, image }) {\n  return (\n    \u003Csection>\n      \u003CStructuredText\n        data={ text }\n        renderInlineRecord={ InlineRecord }\n      \u002F>\n      \u003CDatoImage data={ image.responsiveImage } \u002F>\n    \u003C\u002Fsection>\n  )\n}\n\nfunction InlineRecord ({ record }) {\n  switch (record._modelApiKey) {\n    case 'icon':\n      return (\n        \u003CIcon\n          name={ record.name }\n          class={ `icon--${record.alignment}` }\n        \u002F>\n      )\n    case 'external_link':\n      return (\n        \u003CExternalLink\n          title={ record.title }\n          url={ record.url }\n          class={ 'external-link' }\n        \u002F>\n      )\n    default:\n      console.warn(`No inline record specified for \"${ record._modelApiKey }\"`)\n      return null\n  }\n}",{"__typename":162,"id":221,"title":153,"body":222},"75529624","\u003Cp>The result, rich text with inline components (\u003Ca href=\"https:\u002F\u002Fsterreschans.nl\u002Fcontact\u002F#section-64182282\">view live on website\u003C\u002Fa>):\u003C\u002Fp>",{"__typename":167,"id":224,"image":225,"caption":153,"fullWidth":174,"captionPosition":175},"75529625",{"url":146,"alt":170,"width":171,"height":172},{"__typename":162,"id":227,"title":153,"body":228},"75529626","\u003Cp>Enjoy the enhanced content experience!\u003C\u002Fp>\n\u003Cp>ps. noticed the use of GraphQL fragments and content types in our code? You can read all about it in our blog posts \u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fcomponentize-data-with-graphql-fragments\u002F\">Componentize data with GraphQL fragments\u003C\u002Fa> and \u003Ca href=\"https:\u002F\u002Fwww.voorhoede.nl\u002Fen\u002Fblog\u002Fcms-driven-intellisense-in-your-code-editor\u002F\">CMS-driven IntelliSense in your code editor\u003C\u002Fa>.\u003C\u002Fp>",[],[],[232],{"id":233,"title":234,"slug":235,"blogPosts":236},"WTPJX79URE-O5lpWLJeEHg","Headless CMS","headless-cms",[237,244,261],{"slug":238,"title":239,"date":240,"authors":241},"dropbox-paper-as-a-headless-cms","Dropbox Paper as a headless CMS","2019-01-25T01:00:00.000+01:00",[242],{"name":152,"image":243},{"url":156,"alt":148,"width":157,"height":158},{"slug":245,"title":246,"date":247,"authors":248},"figma-as-a-cms-where-design-and-development-collide","Figma as a CMS; where design and development collide","2022-02-10T01:00:00.000+01:00",[249,255],{"name":250,"image":251},"Bas ",{"url":252,"alt":148,"width":253,"height":254},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683535728-bas-g.jpg",2394,3192,{"name":256,"image":257},"Friso",{"url":258,"alt":148,"width":259,"height":260},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534636-placeholder.jpg",1235,1646,{"slug":262,"title":263,"date":264,"authors":265},"scripted-cms-migrations","Safe and convenient CMS migrations with scripted migrations and sandbox environments","2022-11-25T01:00:00.000+01:00",[266],{"name":267,"image":268},"Frank",{"url":269,"alt":148,"width":270,"height":271},"https:\u002F\u002Fwww.datocms-assets.com\u002F6524\u002F1683534610-frank.jpg",2049,2732,1776256143948]