Introducing Visual Copilot 2.0: Make Figma designs real

Announcing Visual Copilot - Figma to production in half the time

Builder.io logo
Contact Sales
Platform
Developers
Contact Sales

Blog

Home

Resources

Blog

Forum

Github

Login

Signup

×

Visual CMS

Drag-and-drop visual editor and headless CMS for any tech stack

Theme Studio for Shopify

Build and optimize your Shopify-hosted storefront, no coding required

Resources

Blog

Get StartedLogin

‹ Back to blog

Drag-and-drop with Next.js

Setting up visual drag-and-drop page building with Next.js

August 17, 2021

Written By Kapunahele Wong

Last updated: April 13, 2023.

If you have a Next.js application, you can build, edit, and add pages by dragging and dropping elements within Builder.io.

This means that a developer can create the basic structure of an app by generating a Next.js application and then other team members, such as content editors, marketers, and designers, can autonomously iterate and update pages on the fly.

Tip: This article uses Next.js Pages Router. For App Router, visit Integrating Pages.

Goals

To build pages visually with Next.js, this tutorial guides you through:

  • Creating a Next.js app
  • Connecting the Builder.io drag-and-drop page building UI to your new app

Before following these steps to generate a Next.js app, make sure you have Node.js 12.22.0 or later on your computer.

At the command line, run the following command to generate a Next.js app with TypeScript:

npx create-next-app --typescript

When you're prompted for your permission to install create-next-app, say yes.

For this example, name your project my-app.

Change directory with the cd command:

cd my-app

Open this directory in your favorite code editor.

To use drag-and-drop, add Builder as a dependency.

At the command line, use npm to install Builder:

npm install "@builder.io/react"

Start the development server with npm:

npm run dev

Keep your editor open because we'll come back after some set up in Builder.

For more detailed information on Next.js, check out the official Next.js Getting Started.

Icon for Next.js

If you'd rather use a ready-made app, try Builder's Next.js example with step-by-step instructions.

In the pages directory, rename the default index.tsx to [...page].tsx . The double square brackets, [], are how Next.js creates dynamic routes, which means you can create pages with different names in Builder and Next.js can find them all.

Replace the code in [...page].tsx with the following, making sure to add your Public API Key to the builder.init() method.

You will get the Public API Key in a later section in this blog post.

import type { GetStaticPropsContext, InferGetStaticPropsType } from 'next'
import { useRouter } from 'next/router'
import { BuilderComponent, builder, useIsPreviewing } from '@builder.io/react'
import DefaultErrorPage from 'next/error'
import Head from 'next/head'

// put your Public API Key you copied from Builder.io here
const BUILDER_API_KEY = ''
builder.init(BUILDER_API_KEY)

export async function getStaticProps({
  params,
}: GetStaticPropsContext<{ page: string[] }>) {
  const page = await builder.get('page', {
    userAttributes: {
      urlPath: '/' + (params?.page?.join('/') || ''),
    }
  })
  .toPromise() || null

  return {
    props: {
      page,
    },
    revalidate: 5,
  }
}

export async function getStaticPaths() {
  const pages = await builder.getAll('page', {
    options: { noTargeting: true }
  })

  return {
    paths: pages.map((page) => `${page.data?.url}`),
    fallback: true,
  }
}

export default function Page({
  page,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  const router = useRouter()
  if (router.isFallback) {
    return <h1>Loading...</h1>
  }
  const isPreviewing = useIsPreviewing();
  if (!page && !isPreviewing) {
    return (
      <>
        <Head>
          <meta name="robots" content="noindex" />
          <meta name="title"></meta>
        </Head>
        <DefaultErrorPage statusCode={404} />
      </>
    )
  }

  return (
    <>
      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </Head>
      
      <BuilderComponent model="page" content={page} />
    </>
  )
}

This section explains what the code in [...page].tsx is doing at a high level. For more detailed information, see the Next.js documentation.

At the top of the file, the import statements make all the Next.js and Builder resources available that the code in this file needs.

After the imports, you specify the Builder Public API Key and, with builder.init(), initialize connect your app to Builder.

The getStaticProps() function tells you what paths the app is building. Here, Builder gets the page and creates the URL, otherwise, if there's no page, you'll get null and a 404.

export async function getStaticProps({
  params,
}: GetStaticPropsContext<{ page: string[] }>) {
  const page = await builder.get('page', {
    userAttributes: {
      urlPath: '/' + (params?.page?.join('/') || ''),
    }
  })
  .toPromise() || null

  return {
    props: {
      page,
    },
    revalidate: 5,
  }
}

revalidate: 5 means that Next.js attempts to re-generate the page under these conditions:

  • When a request comes in
  • At most once every 5 seconds
  • To check if Builder has updates to the page

The getStaticPaths() function returns a list of page URLs, omits unnecessary data for creating the list, and with fallback: true, checks Builder for any new pages you might have added.

export async function getStaticPaths() {
  const pages = await builder.getAll('page', {
    options: { noTargeting: true },
    omit: "data.blocks"
  })

  return {
    paths: pages.map((page) => `${page.data?.url}`),
     fallback: true,
  }
}

The last section is a regular React component called Page(). It gets the page data and checks that Builder is present. If there's no page and no Builder, Next.js returns a 404. Otherwise, you get your Builder page.

// React Component
export default function Page({
  page,
}: InferGetStaticPropsType<typeof getStaticProps>) {
  const router = useRouter()
  if (router.isFallback) {
    return <h1>Loading...</h1>
  }
  const isPreviewing = useIsPreviewing();

  if (!page && !isPreviewing) {
    return (
      <>
        <Head>
          <meta name="robots" content="noindex" />
          <meta name="title"></meta>
        </Head>
        <DefaultErrorPage statusCode={404} />
      </>
    )
  }

  return (
    <>
      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
      </Head>
      
      <BuilderComponent model="page" content={page} />
    </>
  )
}

Builder adds the ability for your team members–even those who don't code–to create pages and iterate on ideas with a drag-and-drop interface.

Head over to Builder.io to sign up for an account if you don't already have one. Come back when you're logged in.

To enable Builder to open your site in the visual editor, you will need to provide a URL that we can open which has the Builder rendering component in it.

Go to the /models page in Builder and choose your page model.

Then, set the Preview URL to http://localhost:3000. Be sure to include the http://.

For more information on preview URLs, read Editing and Previewing Your Site.

You can find and copy your Public API Key with the following steps:

  1. Within your Builder Space, press Cmd/Ctrl + k to open the Command Palette.
  2. Start to type the letters API into the search field to filter results.
  3. Click your API key to copy to your clipboard.

Alternatively, you can also find your Public API Key in Account Settings for the Space:

  1. Within your Builder Space, go to the Account Settings section.
  2. Click the copy icon to the right of the Public API Key field.

The video below shows both ways to find the Public API Key.

Now, head back to pages/[...page].tsx and paste this key as the value for BUILDER_API_KEY.

Currently, when you go to http://localhost:3000, you should see a 404 page. This is because your app is not ready for you to provide a page to render.

To give your app something to work with, click on the Content icon in the left sidenav:

  1. Go to the Content section of Builder.
  2. Click + New and select Page.
  3. Name the page; for example, home. Builder auto-generates a URL based on the name you provide, but you can customize the URL if you like. This example uses the URL of / to specify localhost:3000.
  4. Choose the blank template.
  5. Drag in a Text block and something like, "I did it!".
  6. When your page is ready, click the Publish button.

The following video demonstrates creating and publishing a Page:

Go to http://localhost:3000 and check out your work. Well done!

If you're getting a 404 but aren't sure why, check these things:

  • Make sure you've published your page in Builder by clicking the Publish Draft button on the upper right corner.
  • Check the URL. If you name the page test2 for example, Builder adds a hyphen, so that the URL segment is test-2.
  • Check that your browser allows insecure content.
  • Make sure your dev server is running (sometimes restarting helps).

For more information on using Next.js or other frameworks with Builder, read the Integrating Pages official documentation or watch the video on how to build a modern site using Next.js.

Use your React components in the Editor

Follow the next article in this series to learn how to use your React components in Builder's Visual Editor.

Share

Twitter
LinkedIn
Facebook
Hand written text that says "A drag and drop headless CMS?"

Introducing Visual Copilot:

A new AI model to turn Figma designs to high quality code using your components.

Try Visual CopilotGet a demo
Newsletter

Like our content?

Join Our Newsletter

Continue Reading
AI12 MIN
Why AI Is Making Dev Skills More Valuable, Not Less
December 3, 2024
ai8 MIN
The Big Lie AI Vendors Keep Telling You
November 27, 2024
AI8 MIN
Generate Figma Designs with AI
November 25, 2024