This project's public API token: APITOKEN
Overview
This covers integrating Plasmic into your existing Next.js codebase.
Want to quickly generate a new codebase with Plasmic already integrated? Use create-plasmic-app instead, or just press the Publish button in your project to push a new repo to GitHub!
Want to generate source code into your codebase (warning: advanced)? Learn about codegen.
Installation
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.
import { initPlasmicLoader } from "@plasmicapp/loader-nextjs";export const PLASMIC = initPlasmicLoader({projects: [{id: "PROJECTID", // ID of a project you are usingtoken: "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 ID and public API token: open the project in Plasmic Studio.
The project ID is in the URL, like: https://studio.plasmic.app/projects/PROJECTID
.
The public API token can be found by clicking the Code toolbar button.
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 remove any existingpages/index.tsx
), orpages/[...catchall].tsx
otherwise (your Plasmic project must not have a page whose route is/
—change the route to something else if you do).
In all cases, the Plasmic page will only be there if there is no existing page for that route.
import * as React from 'react';import {PlasmicComponent,ComponentRenderData,PlasmicRootProvider,extractPlasmicQueryData} from '@plasmicapp/loader-nextjs';import { GetStaticPaths, GetStaticProps } from 'next';import Error from 'next/error';import { useRouter } from 'next/router';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: 'blocking'};};/*** 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 stringconst plasmicPath =typeof catchall === 'string' ? catchall : Array.isArray(catchall) ? `/${catchall.join('/')}` : '/';const plasmicData = await PLASMIC.maybeFetchComponentData(plasmicPath);if (!plasmicData) {// This is some non-Plasmic catch-all pagereturn {props: {}};}// This is a path that Plasmic knows about.const pageMeta = plasmicData.entryCompMetas[0];// Cache the necessary data fetched for the page.const queryCache = await extractPlasmicQueryData(<PlasmicRootProviderloader={PLASMIC}prefetchedData={plasmicData}pageRoute={pageMeta.path}pageParams={pageMeta.params}><PlasmicComponent component={pageMeta.displayName} /></PlasmicRootProvider>);// Pass the data in as props.return {props: { plasmicData, queryCache },// Using incremental static regeneration, will invalidate this page// after 300s (no deploy webhooks needed)revalidate: 300};};/*** Actually render the page!*/export default function CatchallPage(props: { plasmicData?: ComponentRenderData; queryCache?: Record<string, any> }) {const { plasmicData, queryCache } = props;const router = useRouter();if (!plasmicData || plasmicData.entryCompMetas.length === 0) {return <Error statusCode={404} />;}const pageMeta = plasmicData.entryCompMetas[0];return (// Pass in the data fetched in getStaticProps as prefetchedData<PlasmicRootProviderloader={PLASMIC}prefetchedData={plasmicData}prefetchedQueryData={queryCache}pageRoute={pageMeta.path}pageParams={pageMeta.params}pageQuery={router.query}>{// pageMeta.displayName contains the name of the component you fetched.}<PlasmicComponent component={pageMeta.displayName} /></PlasmicRootProvider>);}
Notes:
- You can use incremental static regeneration with
getStaticProps
. - If your project has dynamic pages and you are using SSG, you will need to manually add your dynamic routes to
getStaticPaths
. Learn more about dynamic pages.
Render a single Plasmic page or component
Note: You can instead auto-load all Plasmic pages at the correct routes (recommended) rather than manually loading individual pages—see previous 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.
COMPONENT_OR_PAGEROUTE
refers to the name of the page or component that you want to render, such as Winter22LandingPage
.
If it’s a page, you can also use the route you assigned the page in Plasmic, like /landing
.
// This page will show up at the route /mypageimport {PlasmicRootProvider,PlasmicComponent,ComponentRenderData,extractPlasmicQueryData} from '@plasmicapp/loader-nextjs';import { useRouter } from 'next/router';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('COMPONENT_OR_PAGEROUTE');if (!plasmicData) {throw new Error('No Plasmic design found');}const compMeta = plasmicData.entryCompMetas[0];// Cache the necessary data fetched for the pageconst queryCache = await extractPlasmicQueryData(<PlasmicRootProviderloader={PLASMIC}prefetchedData={plasmicData}pageRoute={compMeta.path}pageParams={compMeta.params}><PlasmicComponent component={compMeta.displayName} /></PlasmicRootProvider>);return {props: {plasmicData,queryCache// ...},// Using incremental static regeneration, will invalidate this page// after 300s (no deploy webhooks needed)revalidate: 300};};// Render the page or component from Plasmic.export default function MyPage(props: { plasmicData: ComponentRenderData; queryCache?: Record<string, any> }) {const router = useRouter();const compMeta = props.plasmicData.entryCompMetas[0];return (<PlasmicRootProviderloader={PLASMIC}prefetchedData={props.plasmicData}prefetchedQueryData={props.queryCache}pageRoute={compMeta.path}pageParams={compMeta.params}pageQuery={router.query}><PlasmicComponent component={compMeta.displayName} /></PlasmicRootProvider>);}
Notes:
- You can skip
getStaticProps
to fetch dynamically at runtime. - Use
getServerSideProps
instead ofgetStaticProps
for SSR. - Here we are using incremental static regeneration with
getStaticProps
, so no deploy webhooks needed.
Adding custom code components
Let your Plasmic Studio users drag/drop and visually manipulate your own custom React components! Learn more.
Step 1
Create a simple example React component:
import * as React from 'react';export interface HelloWorldProps {children?: React.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 2
Add the following to your plasmic-init.ts
to register it:
import { HelloWorld } from './components/HelloWorld';// ...PLASMIC.registerComponent(HelloWorld, {name: 'HelloWorld',props: {verbose: 'boolean',children: 'slot'}});
Step 3
Create a host page at route /plasmic-host
:
import * as React from 'react';import { PlasmicCanvasHost } from '@plasmicapp/loader-nextjs';import { PLASMIC } from '../plasmic-init';export default function PlasmicHost() {return PLASMIC && <PlasmicCanvasHost />;}
Step 4
Start your app:
npm run dev
And check that you see a confirmation message at http://localhost:{props.port}/plasmic-host.
Step 5
Open https://studio.plasmic.app, click the menu for the current project, select “Configure project,” and set it to http://localhost:{props.port}/plasmic-host.
![configure project menu](/static/93fb394b4867d62039b36e8522c52ea3/fe8a1/configure-project-menu.png)
Step 6
Re-open this project (or reload this tab) to see your component listed in the insert menu!
![insert code component](/static/ec4f2de48e48d6da68447744403cf492/5459c/insert-code-component.png)
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.
(Again, the /plasmic-host route itself is a special hidden route not meant for humans to visit; it is only for Plasmic Studio to hook into.)
Note: If you run next export
rather than (say) hosting on Vercel, then by default it exports with .html
suffixes (unlike the routes in the dev server), so you would get /plasmic-host.html
in production. Either include the .html
in your host URL, or suppress exporting with .html
with trailingSlash: true
in your next.config.js.
Using Plasmic components in a shared layout
Shared layouts are useful for components such as navigation headers and footers.
For example, you might have a NavHeader
component designed in Plasmic and want to show it on all pages.
Shared layouts can be defined in pages/_app.js
, called a custom app component.
Here’s what you need to do:
- Move
<PlasmicRootProvider>
from each page to_app.js
, - In each page’s
getStaticProps
, fetch Plasmic data, including components used by the shared layout. - In
_app.js
, pass the Plasmic data to<PlasmicRootProvider>
.
Example with NavHeader
component:
import { PlasmicRootProvider } from '@plasmicapp/loader-nextjs';import { PLASMIC } from '../plasmic-init';export default function CustomApp({ Component, pageProps }) {return (// The data from each page's `getStaticProps` are in `pageProps`.<PlasmicRootProvider loader={PLASMIC} prefetchedData={pageProps.plasmicData}><PlasmicComponent component="NavHeader" /><Component {...pageProps} /></PlasmicRootProvider>);}
import { useRouter } from 'next/router';import { PageParamsProvider } from '@plasmicapp/loader-nextjs';import { PLASMIC } from '../plasmic-init';export function getStaticProps() {// Be sure to also fetch data for `NavHeader`const plasmicData = await PLASMIC.fetchComponentData('SomePage', 'NavHeader');return {props: {plasmicData}};}export default function SomePage() {const router = useRouter();// no need for <PlasmicRootProvider />return (<PageParamsProvider route={router.pathname} params={router.query} query={router.query}><PlasmicComponent component="SomePage" /></PageParamsProvider>);}
There’s much more to explore!
For example:
- Explore what you can do with code components.
- Render different variants of your pages/components.
- Override the content or props in your design.
- Add hooks for state and behavior to any component.
- (Advanced) Use Plasmic as a UI builder for developers.
Continue learning in the full docs.