Editmode allows you to turn plain text in your Next.js app into easily inline-editable content that can be managed safely by your whole team.
Next.js is an open-source production-ready React framework used to build web applications that are either static or rendered on the server-side, with smart bundling & a config-free setup right out of the gate.
Adding Editmode to an existing Next.js codebase
1. Add editmode-react to your codebase
npminstalleditmode-react
yarnaddeditmode-react
2. Wrap your app in the Editmode provider.
import {Editmode} from"editmode-react"// For demo purposes, we'll use a "Home" page function.// In a real-world setting, the best set-up is to use a <Layout /> component// which all other pages inherit from, to ensure that all pages are // wrapped with the <Editmode /> provider. exportdefaultfunctionHome() {return ( <EditmodeprojectId="prj_Y5HfCBS4rqZg"> {/* Replace with your own project id. */} <section></section> </Editmode> );}
import { Editmode } from"editmode-react";// Branches are used to create separate "versions" of your content, which can// be useful for staging, running a/b tests, or developing locally on teams.// Branches are created within the content hub at https://app.editmode.com// Specifying a branch id when initializing Editmode will load all content// from that specific branch.exportdefaultfunctionHome() {return ( <EditmodeprojectId={project_id} branchId={branch_id}> <section></section> </Editmode> );}
import { Editmode } from"editmode-react";import { defaultChunks } from"./data/defaultChunks";// Editmode is smart about fetching and caching content to ensure that 1. Your// app/site always remains fast, and 2. Users always see the most recent content.// While Editmode is capable of loading content direct from our CDN, some // customers like to also bundle a resource file within their codebase that will // provide content in the event that the API fails. This can // be achieved by passing an object with default content to the Editmode provider// on initialization. The creation of this file can be automated via our API.// See https://snack.expo.io/@editmode/algolia-demo for an interactive demo// of this setupexportdefaultfunctionHome() {return ( <EditmodeprojectId={project_id} defaultChunks={defaultChunks}> <section></section> </Editmode> );}
For more info/best practices on how to implement the <Layout /> pattern, consult our starter repo here.
3. Use the Editmode helpers in your codebase.
import { Chunk } from"editmode-react";functionExample() {return ( <section> {/* Reference a standalone chunk using the chunk identifier */} <Chunkidentifier="cnk_7019e843b76e2d0395ab" /> {/* You can also reference a chunk using its content key */} <Chunkidentifier="company_name" /> {/* Provide default content when referencing a chunk */} {/* Default content is a precaution that will get rendered in the event that the content cannot be served from the Editmode API. */} <Chunkidentifier="company_name"> Our Company </Chunk> </section> );}
import { Chunk } from"editmode-react";functionExample() {return ( <section> {/* Editmode has two types of chunks - "standalone" and "hybrid". Standalone chunks can only store a single piece of content, whereas hybrid (or collection) chunks can have many fields. These fields are pre-specified in the Content Hub at https://app.editmode.com */} <Chunkidentifier="home_hero"field="Headline" /> <Chunkidentifier="home_hero"field="Tagline" /> <Chunkidentifier="home_hero"field="Description" /> </section> );}
import { Chunk } from"editmode-react";// By default, an editable chunk is rendered to the client as an unstyled <em-span />// This can cause unwanted behaviour from a styling perspective, so you can tell // Editmode to add a class to the wrapper.functionExample() {return ( <section> <Chunkidentifier="company_name"className="bg-white rounded shadow p-6" /> </section> );}
import Head from"next/head";import {Editmode, Chunk, ChunkCollection, ChunkFieldValue, useGetChunk} from"editmode-react"exportdefaultfunctionHome() {return ( <EditmodeprojectId="prj_Y5HfCBS4rqZg" > <divclassName="container mx-auto"> {/* Render a piece of standalone content with inline editing */} <Chunkidentifier="logo_icon"className="w-5 text-primary" /> {/* Image Chunk */} <Chunkidentifier="company_name" /> {/* Plain Text Chunk */} {/* Render content from a collection, with inline editing */} <ChunkCollectionidentifier="testimonials" > <ChunkFieldValueidentifier="Name" /> <ChunkFieldValueidentifier="Role" /> <ChunkFieldValueidentifier="Comment" /> </ChunkCollection> {/* Access the raw value of a chunk. (No inline editing) */} <Head> <title>{useGetChunk("company_tagline")}</title> </Head> </div> </Editmode> )}
Working with collections
Chunk collections are simply a way to group chunks and can be used to render repeatable content. Each collection can contain many properties and each property can hold different types of information.
A good use case example would be creating a "Team Member" collection. It may have Full Name, Title and Headshot properties. Within your Next.js app, you may want to display the name, title and headshot of all your team members (i.e. all chunks within the Team Member collection). You can do this by passing the chunk collection identifier as a prop to the ChunkCollection component. For example...
import { ChunkCollection, ChunkFieldValue } from"editmode-react";functionExample() {return ( <sectionclassName="testimonials"> {/* Render content from a collection, with inline editing */} <ChunkCollectionidentifier="col_MFxBu6fiTyRM" > <ChunkFieldValueidentifier="fld_LscoanYMdCOy" /> <ChunkFieldValueidentifier="fld_Iq94B0LyQxGc" /> <ChunkFieldValueidentifier="fld_LyRI6y3v2D8ct" /> </ChunkCollection> {/* Use content keys for better readability */} <ChunkCollectionidentifier="testimonials" > <ChunkFieldValueidentifier="Name" /> <ChunkFieldValueidentifier="Role" /> <ChunkFieldValueidentifier="Comment" /> </ChunkCollection> {/* Only render collection items with certain tags */} <ChunkCollectionidentifier="testimonials"tags={["home_testimonials"]}> <ChunkFieldValueidentifier="Name" /> <ChunkFieldValueidentifier="Role" /> <ChunkFieldValueidentifier="Comment" /> </ChunkCollection> </section> );}
import { ChunkCollection, ChunkFieldValue, getChunk } from"editmode-react";// Often, when iterating through a collection of content, your UI will need // to access the raw values, instead of rendering inline-editable chunks. // For this we use getChunk(), along with ChunkCollection.functionExample() {return ( <sectionclassName="meet_the_team"> <ChunkCollectionidentifier="navigation_items"> {(getChunk, chunk) => {return (if (getChunk(chunk,"Title")) { {/* Render an editable inline field */} <ChunkFieldValue identifier="Title"/> {/* Render a link using the chunk field values*/} <a href={getChunk(chunk,"Url")}> {getChunk(chunk, "Title")} </a> } ) }} </ChunkCollection> </section> );}
Full Reference
A full list of components, functions, and props can be found here 👇
For green-field codebases, the best way to get started is by forking our "Marketing Site in a Box" repository (specifically the "Lagos" theme). We spent a lot of time to ensure it has all the basics covered, along with examples.
This workflow will be available as an npx command soon, but for now you can easily get started by cloning the repo, navigating to the "Lagos" theme directory, and removing the parts you don't need.
git clone https://github.com/editmodelabs/msiab
cd msiab/themes/lagos
yarn install
yarn dev