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> );}
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.
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...
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.
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 setup
export default function Home() {
return (
<Editmode projectId={project_id} defaultChunks={defaultChunks}>
<section></section>
</Editmode>
);
}
import { Chunk } from "editmode-react";
function Example() {
return (
<section>
{/* Reference a standalone chunk using the chunk identifier */}
<Chunk identifier="cnk_7019e843b76e2d0395ab" />
{/* You can also reference a chunk using its content key */}
<Chunk identifier="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.
*/}
<Chunk identifier="company_name">
Our Company
</Chunk>
</section>
);
}
import { Chunk } from "editmode-react";
function Example() {
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
*/}
<Chunk identifier="home_hero" field="Headline" />
<Chunk identifier="home_hero" field="Tagline" />
<Chunk identifier="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.
function Example() {
return (
<section>
<Chunk identifier="company_name" className="bg-white rounded shadow p-6" />
</section>
);
}
import Head from "next/head";
import {Editmode, Chunk, ChunkCollection, ChunkFieldValue, useGetChunk} from "editmode-react"
export default function Home() {
return (
<Editmode projectId="prj_Y5HfCBS4rqZg" >
<div className="container mx-auto">
{/* Render a piece of standalone content with inline editing */}
<Chunk identifier="logo_icon" className="w-5 text-primary" /> {/* Image Chunk */}
<Chunk identifier="company_name" /> {/* Plain Text Chunk */}
{/* Render content from a collection, with inline editing */}
<ChunkCollection identifier="testimonials" >
<ChunkFieldValue identifier="Name" />
<ChunkFieldValue identifier="Role" />
<ChunkFieldValue identifier="Comment" />
</ChunkCollection>
{/* Access the raw value of a chunk. (No inline editing) */}
<Head>
<title>{useGetChunk("company_tagline")}</title>
</Head>
</div>
</Editmode>
)
}
import { ChunkCollection, ChunkFieldValue } from "editmode-react";
function Example() {
return (
<section className="testimonials">
{/* Render content from a collection, with inline editing */}
<ChunkCollection identifier="col_MFxBu6fiTyRM" >
<ChunkFieldValue identifier="fld_LscoanYMdCOy" />
<ChunkFieldValue identifier="fld_Iq94B0LyQxGc" />
<ChunkFieldValue identifier="fld_LyRI6y3v2D8ct" />
</ChunkCollection>
{/* Use content keys for better readability */}
<ChunkCollection identifier="testimonials" >
<ChunkFieldValue identifier="Name" />
<ChunkFieldValue identifier="Role" />
<ChunkFieldValue identifier="Comment" />
</ChunkCollection>
{/* Only render collection items with certain tags */}
<ChunkCollection identifier="testimonials" tags={["home_testimonials"]}>
<ChunkFieldValue identifier="Name" />
<ChunkFieldValue identifier="Role" />
<ChunkFieldValue identifier="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.
function Example() {
return (
<section className="meet_the_team">
<ChunkCollection identifier="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>
);
}
git clone https://github.com/editmodelabs/msiab
cd msiab/themes/lagos
yarn install
yarn dev