Get started with Next.js

Overview

This covers integrating Plasmic into your existing Next.js codebase.

Want to quickly generate a new codebase with Plasmic already integrated? Follow this guide instead!

Installation

Copy
npm install @plasmicapp/loader-nextjs
# or yarn add @plasmicapp/loader-nextjs

Initialization

Initialize Plasmic with the project ID and public API token. Define this in its own module to make it available globally.

./plasmic-init.ts
Copy
import { initPlasmicLoader } from "@plasmicapp/loader-nextjs";
export const PLASMIC = initPlasmicLoader({
projects: [
{
id: "PROJECTID", // ID of a project you are using
token: "APITOKEN" // API token for that project
}
],
// Fetches the latest revisions, whether or not they were unpublished!
// Disable for production to ensure you render only published changes.
preview: true,
})

To find your project’s public API token: open the project in Plasmic Studio, and click the Code toolbar button.

Render a single Plasmic page or component

Note: You can auto-load all Plasmic pages at the correct routes (recommended) rather than manually loading individual pages—see next section.

We use Next.js’s getStaticProps() to fetch the design statically.

For example, to render a page: add a file under pages/, named for your desired route, with the following code:

pages/mypage.tsx
Copy
// This page will show up at the route /mypage
import {
initPlasmicLoader,
PlasmicRootProvider,
PlasmicComponent,
ComponentRenderData
} from '@plasmicapp/loader-nextjs';
import { PLASMIC } from '../plasmic-init';
// Statically fetch the data needed to render Plasmic pages or components.
export const getStaticProps = async () => {
// You can pass in multiple page paths or component names.
const plasmicData = await PLASMIC.fetchComponentData('PATH_OR_COMPONENT');
return {
props: {
plasmicData
// ...
}
};
};
// Render the page or component from Plasmic.
export default function MyPage(props: { plasmicData: ComponentRenderData }) {
return (
<PlasmicRootProvider loader={PLASMIC} prefetchedData={props.plasmicData}>
<PlasmicComponent component="PATH_OR_COMPONENT" />
</PlasmicRootProvider>
);
}

Notes:

  • You can skip getStaticProps to fetch dynamically at runtime.
  • Use getServerSideProps instead of getStaticProps for SSR.
  • You can use incremental static regeneration with getStaticProps.

Auto load all Plasmic pages

To automatically render all Plasmic-defined pages at the routes specified in Plasmic, create a Next.js catch-all page.

Create either:

  • pages/[[...catchall]].tsx if you want the / route to render the corresponding Plasmic page (you must not have an existing pages/index.tsx), or
  • pages/[...catchall].tsx otherwise.

In all cases, the Plasmic page will only be there if there is no existing page already in pages/... for that route.

pages/[[...catchall]].tsx
Copy
import * as React from 'react';
import {
PlasmicComponent,
ComponentRenderData,
PlasmicRootProvider,
initPlasmicLoader
} from '@plasmicapp/loader-nextjs';
import { GetStaticPaths, GetStaticProps } from 'next';
import Error from 'next/error';
import { PLASMIC } from '../plasmic-init';
/**
* Use fetchPages() to fetch list of pages that have been created in Plasmic
*/
export const getStaticPaths: GetStaticPaths = async () => {
const pages = await PLASMIC.fetchPages();
return {
paths: pages.map((page) => ({
params: { catchall: page.path.substring(1).split('/') }
})),
fallback: false
};
};
/**
* For each page, pre-fetch the data we need to render it
*/
export const getStaticProps: GetStaticProps = async (context) => {
const { catchall } = context.params ?? {};
// Convert the catchall param into a path string
const plasmicPath =
typeof catchall === 'string' ? catchall : Array.isArray(catchall) ? `/${catchall.join('/')}` : '/';
const plasmicData = await PLASMIC.maybeFetchComponentData(plasmicPath);
if (plasmicData) {
// This is a path that Plasmic knows about; pass the data
// in as props
return {
props: { plasmicData }
};
} else {
// This is some non-Plasmic catch-all page
return {
props: {}
};
}
};
/**
* Actually render the page!
*/
export default function CatchallPage(props: { plasmicData?: ComponentRenderData }) {
const { plasmicData } = props;
if (!plasmicData || plasmicData.entryCompMetas.length === 0) {
return <Error statusCode={404} />;
}
return (
// Pass in the data fetched in getStaticProps as prefetchedData
<PlasmicRootProvider loader={PLASMIC} prefetchedData={plasmicData}>
{
// plasmicData.entryCompMetas[0].name contains the name
// of the component you fetched.
}
<PlasmicComponent component={plasmicData.entryCompMetas[0].name} />
</PlasmicRootProvider>
);
}

Notes:

Add custom code components

Let your Plasmic Studio users drag/drop and visually manipulate any React component! (Learn more.)

Step 1

Create a special hidden page at route /plasmic-host.

pages/plasmic-host.tsx
Copy
import * as React from 'react';
import { PlasmicCanvasHost } from '@plasmicapp/loader-nextjs';
import Head from 'next/head';
// Some Next.js app configurations will cause a plain `import '../plasmic-init'` to be ignored.
import { PLASMIC } from '../plasmic-init';
export default function Host() {
return (
PLASMIC && (
<div>
<Head>
<script
dangerouslySetInnerHTML={{
__html: `
!function(){const n=window,i="__REACT_DEVTOOLS_GLOBAL_HOOK__",o="__PlasmicPreambleVersion",t=function(){}
if(void 0!==n){if(n.parent!==n)try{n[i]=n.parent[i]}catch(e){}if(!n[i]){const r=new Map
n[i]={supportsFiber:!0,renderers:r,inject:function(n){r.set(r.size+1,n)},onCommitFiberRoot:t,onCommitFiberUnmount:t}}n[i][o]||(n[i][o]
="1")}}()`
}}
></script>
</Head>
<PlasmicCanvasHost />
</div>
)
);
}

Step 2

Start your app:

Copy
npm run dev

And check that you see a confirmation message at http://localhost:3000/plasmic-host.

Step 3

Create a simple example React component:

components/HelloWorld.tsx
Copy
import React from 'react';
export interface HelloWorldProps {
children?: ReactNode;
className?: string;
verbose?: boolean;
}
export function HelloWorld({ children, className, verbose }: HelloWorldProps) {
return (
<div className={className} style={{ padding: '20px' }}>
<p>Hello there! {verbose && 'Really nice to meet you!'}</p>
<div>{children}</div>
</div>
);
}

Step 4

Add the following to your plasmic-init.ts to register it:

./plasmic-init.ts
Copy
import { HelloWorld } from './components/HelloWorld';
// ...
const PLASMIC = initPlasmicLoader(/* ... */);
PLASMIC.registerComponent(HelloWorld, {
name: 'HelloWorld',
props: {
verbose: 'boolean',
children: 'slot'
}
});

Step 5

Open https://studio.plasmic.app, click the menu for the current project, select "Configure project," and set it to http://localhost:3000/plasmic-host.

configure project menu

Step 6

Re-open this project (or reload this tab) to see your component listed in the insert menu!

insert code component

Later, after you deploy the route to production, update the project to use your production host URL instead, such as https://my-app.com/plasmic-host. This way, other members of your team (who can’t access your localhost dev server) will be able to open and edit the project in Plasmic.

Learn more about code components.

There’s much more to explore!

For example:

Continue learning in the full docs.