A common approach to website development is to build components that can be reused across different web pages. The benefit to this approach is that you end up doing less duplicate work by managing the components rather than managing duplicate content across different pages. Popular JavaScript frameworks like React, Vue and Angular utilize this concept on the application code level to much success. How can we benefit from this approach on the content management level? In this tutorial I’m going to show you how to build a component-based website using React and the Cosmic JS CMS. The goal is to save developers and content managers time and provide a scalable content model. Build the Content Model * Prereqs: This article assumes you have an understanding of Cosmic JS concepts: Object Types, Objects and Metafields. If you need to brush up on these concepts, go to the Getting Started guide. Using Cosmic JS Object Types and Metafields, we can create composable components that can be used across website pages. For our example we will create three Object Types: PagesSections (components used in Pages)Team Members (used in the Team Section) Let’s look at each Object Type: Pages All Pages will include the following: Title (Text)Content (HTML Textarea)Sections (Multiple Objects Relationship Metafield) The Multiple Objects Relationship Metafield will be used to manage the Page Sections. Team Members Metafields: Name (Text Metafield)Image (File Metafield)Quote (Plain Textarea Metafield) Sections The Sections Object Type will be more dynamic and allow for different Metafields. Team Section Metafields: HeadlineMultiple Object Relationship Metafield (Team) NameImageQuote Add your team members: Signup SectionMetafields: Headline (Text Metafield)Image (File Metafield)Content (HTML Metafield)CTA (Text Metafield) Add Sections to Pages Now that we have our Sections set up, we can add them to our Pages: Code it up Now that we have our content saved, let’s do some coding. Download the React starter: git clone https://github.com/cosmicjs/react-starter Now go into the Page component and edit it to look like this: // page.js import SectionList from './section-list' export default ({ page }) => ( <div> <h1>{page.title}</h1> <div dangerouslySetInnerHTML={{__html: page.content}}></div> <SectionList sections={page.metadata.sections}/> </div> ) As you can see, we’ve added Section List on our Page Object. Our Section List and Section components looks like this: // section-list.js import TeamSection from './sections/team' import SignupSection from './sections/signup' export default ({ sections }) => ( <div> { sections.map(section => { if (section.metadata.team) return <TeamSection section={section} /> if (section.metadata.cta) return <SignupSection section={section} /> }) } </div> ) // signup.js export default ({ section }) => ( <div> <h3>{section.metadata.headline}</h3> <div dangerouslySetInnerHTML={{ __html: section.metadata.content }}></div> <div><img src={section.metadata.image.imgix_url} /></div> <div><button>{section.metadata.cta}</button></div> </div> ) // team.js export default ({ section }) => ( <div> <h3>{section.metadata.headline}</h3> { section.metadata.team.map(person => { return ( <div key={person._id}> <div>{person.metadata.name}</div> <div>{person.metadata.quote}</div> <div><img src={person.metadata.image.imgix_url} /></div> </div> ) }) } </div> ) Output of the Section component is determined by the data passed via the section prop. In Conclusion The Cosmic JS CMS is a great solution for building component-based websites. In our example, we created a Page Object with a Multiple Object Metafield connected to a Sections Object Type to add our Section components. The benefit to this approach is that we can now manage the section content in one place and reuse it across pages without having to go into each page to edit duplicate data. I hope you found this useful. If you have any further questions, join our community on Slack and reach out to us on Twitter. Photo by Lance Anderson on Unsplash A common approach to website development is to build components that can be reused across different web pages. The benefit to this approach is that you end up doing less duplicate work by managing the components rather than managing duplicate content across different pages. Popular JavaScript frameworks like React, Vue and Angular utilize this concept on the application code level to much success. How can we benefit from this approach on the content management level? In this tutorial I’m going to show you how to build a component-based website using React and the Cosmic JS CMS . The goal is to save developers and content managers time and provide a scalable content model. Cosmic JS CMS Build the Content Model * Prereqs: This article assumes you have an understanding of Cosmic JS concepts: Object Types, Objects and Metafields. If you need to brush up on these concepts, go to the Getting Started guide . Getting Started guide Using Cosmic JS Object Types and Metafields, we can create composable components that can be used across website pages. For our example we will create three Object Types: Pages Sections (components used in Pages) Team Members (used in the Team Section) Pages Sections (components used in Pages) Team Members (used in the Team Section) Let’s look at each Object Type: Pages All Pages will include the following: Title (Text) Content (HTML Textarea) Sections (Multiple Objects Relationship Metafield) Title (Text) Content (HTML Textarea) Sections (Multiple Objects Relationship Metafield) The Multiple Objects Relationship Metafield will be used to manage the Page Sections. Team Members Metafields: Name (Text Metafield) Image (File Metafield) Quote (Plain Textarea Metafield) Name (Text Metafield) Image (File Metafield) Quote (Plain Textarea Metafield) Sections The Sections Object Type will be more dynamic and allow for different Metafields. Team Section Team Section Metafields: Headline Multiple Object Relationship Metafield (Team) Headline Multiple Object Relationship Metafield (Team) Name Image Quote Name Image Quote Add your team members: Signup Section Metafields: Signup Section Headline (Text Metafield) Image (File Metafield) Content (HTML Metafield) CTA (Text Metafield) Headline (Text Metafield) Image (File Metafield) Content (HTML Metafield) CTA (Text Metafield) Add Sections to Pages Add Sections to Pages Now that we have our Sections set up, we can add them to our Pages: Code it up Now that we have our content saved, let’s do some coding. Download the React starter : React starter git clone https://github.com/cosmicjs/react-starter git clone https://github.com/cosmicjs/react-starter git clone https: //gi thub.com /cosmicjs/ react-starter git clone https: //gi thub.com /cosmicjs/ react-starter Now go into the Page component and edit it to look like this: // page.js import SectionList from './section-list' export default ({ page }) => ( <div> <h1>{page.title}</h1> <div dangerouslySetInnerHTML={{__html: page.content}}></div> <SectionList sections={page.metadata.sections}/> </div> ) // page.js import SectionList from './section-list' export default ({ page }) => ( <div> <h1>{page.title}</h1> <div dangerouslySetInnerHTML={{__html: page.content}}></div> <SectionList sections={page.metadata.sections}/> </div> ) // page.js import SectionList from './section-list' export default ({ page }) => ( < div > < h1 > {page.title} </ h1 > < div dangerouslySetInnerHTML = {{__html: page.content }}> </ div > < SectionList sections = {page.metadata.sections}/ > </ div > ) // page.js import SectionList from './section-list' export default ({ page }) => ( < div > < h1 > {page.title} </ h1 > < div dangerouslySetInnerHTML = {{__html: page.content }}> </ div > < SectionList sections = {page.metadata.sections}/ > </ div > As you can see, we’ve added Section List on our Page Object. Our Section List and Section components looks like this: // section-list.js import TeamSection from './sections/team' import SignupSection from './sections/signup' export default ({ sections }) => ( <div> { sections.map(section => { if (section.metadata.team) return <TeamSection section={section} /> if (section.metadata.cta) return <SignupSection section={section} /> }) } </div> ) // section-list.js import TeamSection from './sections/team' import SignupSection from './sections/signup' export default ({ sections }) => ( <div> { sections.map(section => { if (section.metadata.team) return <TeamSection section={section} /> if (section.metadata.cta) return <SignupSection section={section} /> }) } </div> ) // section-list.js import TeamSection from './sections/team' import SignupSection from './sections/signup' export default ({ sections }) => ( < div > { sections.map(section => { if (section.metadata.team) return < TeamSection section = {section} /> if (section.metadata.cta) return < SignupSection section = {section} /> }) } </ div > ) // section-list.js import TeamSection from './sections/team' import SignupSection from './sections/signup' export default ({ sections }) => ( < div > { sections.map(section => { if (section.metadata.team) return < TeamSection section = {section} /> if (section.metadata.cta) return < SignupSection section = {section} /> }) } </ div > // signup.js export default ({ section }) => ( <div> <h3>{section.metadata.headline}</h3> <div dangerouslySetInnerHTML={{ __html: section.metadata.content }}></div> <div><img src={section.metadata.image.imgix_url} /></div> <div><button>{section.metadata.cta}</button></div> </div> ) // signup.js export default ({ section }) => ( <div> <h3>{section.metadata.headline}</h3> <div dangerouslySetInnerHTML={{ __html: section.metadata.content }}></div> <div><img src={section.metadata.image.imgix_url} /></div> <div><button>{section.metadata.cta}</button></div> </div> ) // signup.js export default ({ section }) => ( < div > < h3 > {section.metadata.headline} </ h3 > < div dangerouslySetInnerHTML = {{ __html: section.metadata.content }}> </ div > < div > < img src = {section.metadata.image.imgix_url} /> </ div > < div > < button > {section.metadata.cta} </ button > </ div > </ div > ) // signup.js export default ({ section }) => ( < div > < h3 > {section.metadata.headline} </ h3 > < div dangerouslySetInnerHTML = {{ __html: section.metadata.content }}> </ div > < div > < img src = {section.metadata.image.imgix_url} /> </ div > < div > < button > {section.metadata.cta} </ button > </ div > </ div > // team.js export default ({ section }) => ( <div> <h3>{section.metadata.headline}</h3> { section.metadata.team.map(person => { return ( <div key={person._id}> <div>{person.metadata.name}</div> <div>{person.metadata.quote}</div> <div><img src={person.metadata.image.imgix_url} /></div> </div> ) }) } </div> ) // team.js export default ({ section }) => ( <div> <h3>{section.metadata.headline}</h3> { section.metadata.team.map(person => { return ( <div key={person._id}> <div>{person.metadata.name}</div> <div>{person.metadata.quote}</div> <div><img src={person.metadata.image.imgix_url} /></div> </div> ) }) } </div> ) // team.js export default ({ section }) => ( < div > < h3 > {section.metadata.headline} </ h3 > { section.metadata.team.map(person => { return ( < div key = {person._id} > < div > {person.metadata.name} </ div > < div > {person.metadata.quote} </ div > < div > < img src = {person.metadata.image.imgix_url} /> </ div > </ div > ) }) } </ div > ) // team.js export default ({ section }) => ( < div > < h3 > {section.metadata.headline} </ h3 > { section.metadata.team.map(person => { return ( < div key = {person._id} > < div > {person.metadata.name} </ div > < div > {person.metadata.quote} </ div > < div > < img src = {person.metadata.image.imgix_url} /> </ div > </ div > ) }) } </ div > Output of the Section component is determined by the data passed via the section prop. Section Section section section In Conclusion The Cosmic JS CMS is a great solution for building component-based websites. In our example, we created a Page Object with a Multiple Object Metafield connected to a Sections Object Type to add our Section components. The benefit to this approach is that we can now manage the section content in one place and reuse it across pages without having to go into each page to edit duplicate data. I hope you found this useful. If you have any further questions, join our community on Slack and reach out to us on Twitter. join our community on Slack Photo by Lance Anderson on Unsplash Lance Anderson Unsplash