Stackbit is a website builder that gives both technical and non-technical people a lot of power when creating their websites. It can be used to create portfolio websites, blogs, or any type of website if you wish to extend it to your use case.

In this tutorial, you'll learn how to create a blog with Stackbit using its Next.js starter theme. You'll also learn how to add custom pages for Content Models by creating an Authors page.

Project Setup

Start by choosing one of the Starter theme. This tutorial will be focused on the Starter theme.

Then, choose a name for your new project.

If you're not signed in you'll then be asked to either create an account or sign in. I recommend creating an account with GitHub as it will be easier to connect your repository to it then.

You'll then have your website ready for customization.

Notice that your website will be deployed on a free Stackbit subdomain. So, you'll be able to view it online right away.

Transfer Repository to Your Account

The next step is to transfer the website codebase to your GitHub account. This makes it possible for you to make changes to the website's codebase and add new content models.

Click on the gear icon at the top left. Then, under "Connected Services" you'll see GitHub and you'll be able to Request Repo Transfer.

When you click on that you'll receive an email to accept the transfer. Once you click on the link in the email, the transfer will begin and might take a couple of minutes.

Once the transfer is done, you'll have your website's codebase in you GitHub account.

Understanding the Branches

In your GitHub repository, you'll have 2 branches: the master branch and the preview branch.

The master branch is the deployed version that everyone can see when they go on your website.

The preview branch is what you can see when you log in on Stackbit. Think of it as a draft version. Once you think the changes are ready to be deployed on the main website, you can either push the changes to the master branch manually or just click the "Publish" button at the top right in your Stackbit app.

Set Up Local Development

Stackbit has a code editor that you can use right in your Stackbit app by clicking on the code icon in the sidebar.

Once you make a change in the code, it will be automatically committed to the preview branch which is what you see in your Stackbit app.

Alternatively, you  can work on your website's development locally. To do that, click on the gear icon at the top left again. Under "Envoironment" you'll see "Local Development" with steps you can copy and paste into your terminal directly.

Please note that if you haven't transferred the codebase into your GitHub account you won't be able to see these tips.

As mentioned under "Local Development", once you push commits to the preview branch, the visual editor in your Stackbit app will update automatically.

Creating Posts

There are 2 ways to create posts: through the visual editor or through the code editor.

Visual Editor

On your Stackbit app, if you press the second icon "CMS" you'll be able to edit and add pages and blog posts on your website.

Try clicking on "Post" then "Add new Post". You'll be able to enter information like slug and title. Then, you can select a feature image and the author.

You can then use the content editor, which has text formatting you can use but also supports raw markdown editing by pressing the Raw MD button.

All changes you make to posts are automatically committed to the preview branch. Once you publish them they'll be live on your deployed website.

Code Editor

To add posts in the code editor, go to content then pages. You'll see all pages there in markdown files, where the names of the files are the slugs of the pages.

You'll also find a blog directory which holds all posts inside it. To add a blog post create a new file with its name the slug you want for the post. Then, add in it the following information:

---
title: Test Post
layout: PostLayout
date: '2021-07-01'
author: content/data/team/hugh-saturation.json
excerpt: >-
  Sed in facilisis dui. Nulla molestie risus in mi dapibus, eget porta lorem
  semper. Donec sed facilisis nibh.
featuredImage:
  type: ImageBlock
  url: /images/post-2.jpg
  altText: Post Image
bottomSections:
  - elementId: ''
    variant: variant-c
    colors: colors-a
    title: Read next
    recentCount: 3
    styles:
      self:
        height: auto
        width: wide
        margin: ['mt-0', 'mb-0', 'ml-0', 'mr-0']
        padding: ['pt-12', 'pb-56', 'pr-4', 'pl-4']
        justifyContent: center
      title:
        textAlign: center
      subtitle:
        textAlign: center
      actions:
        justifyContent: center
    type: RecentPostsSection
---

This is test post

Everything between the opening and closing 3 dashes are the values of the fields you enter in your visual editor. That includes the title, author, feature image, and more.

Then, after the three dashes is the markdown content of the post. This is the content you'd enter in the text editor in the visual Stackbit app, but it should be in markdown format.

Once you're done, save the new file and commit it to the preview branch. You'll be able to see it in the visual editor among the CMS.

If you also open the Blog page in your Stackbit app or open the website locally, you should see the post you added among other existing posts.

Add Pages for Authors

In this section, you'll start to customize your Stackbit starter. You'll be adding a new predefined type of page to display authors. You'll need to create a layout specific for that page before creating that page.

Add Page to Content Models

Open stackbit.yaml in the root of your website's code and add the following under contentModels:

contentModels:
	...
    PersonFeedLayout:
    	isPage: true
    	singleInstance: true
    	urlPath: '/authors'
    	file: 'authors.md'
    	newFilePath: 'authors.md'

You're adding a new layout PersonFeedLayout. You can read more about content model fields in Stackbit's documentation, but briefly:

  1. If isPage is set to true the UI will allow you to create pages using this model.
  2. singleInstance means that this page can only be created once.
  3. urlPath is the path that this page will be found on.
  4. file is the markdown file that holds the data and content for this page. Since this is a page, its path is relative to content/pages
  5. newFilePath is the file that should be created when this page is created through the UI. Similarly, since this content model is a page the path is relative to content/pages.

Define the Content Model Fields

In this section, you'll define the fields of the new content model PersonFeedLayout. This means that when you try to create the page through the UI, these fields is what you will see.

To do that, create the file .stackbit/models/PersonFeedLayout.yaml with the following content:

name: PersonFeedLayout
label: Authors
labelField: title
layout: PersonFeedLayout
hideContent: true
extends:
  - Seo
fields:
  - type: string
    name: title
    label: Title
    default: This is a page title
  - type: list
    name: topSections
    label: Top Sections
    items:
      type: model
      groups:
        - sectionComponent
  - type: list
    name: bottomSections
    label: Bottom Sections
    items:
      type: model
      groups:
        - sectionComponent
  - type: style
    name: styles
    styles:
      title:
        fontWeight: ['400', '700']
        fontStyle: ['normal', 'italic']
        textAlign: ['left', 'center', 'right']
    default:
      title:
        textAlign: center

You can learn more about Models in Stackbit through their documentation, but briefly the items under fields are what you'll see in the UI and the fields you can enter for this content model. This content model has 4 fields:

  1. title: the title of the page
  2. topSections: Sections you want to add to the top of the page. This is useful if you want to allow users using the visual editor to add custom sections before your defined layout.
  3. bottomSections: Similarly to topSections, you'll allow users using the visual editor to add custom sections after the defined layout.
  4. styles: Allow the users using the visual editor to customize some of the style of the layout.

Create New Layout

Next, you'll be creating the PersonFeedLayout which will hold the implementation of the Authors page.

Create a new file src/components/layouts/PersonFeedLayout/index.tsx with the following content:

import * as React from 'react';

import ImageBlock from '../../molecules/ImageBlock';
import { getBaseLayoutComponent } from '../../../utils/base-layout';
import { getComponent } from '../../components-registry';

export default function PageLayout(props) {
    const { page, site } = props;
    const BaseLayout = getBaseLayoutComponent(page.baseLayout, site.baseLayout);
    const topSections = page.topSections || [];
    const authors = page.authors || [];
    const bottomSections = page.bottomSections || [];

    return (
        <BaseLayout page={page} site={site}>
            <main id="main" className="sb-layout sb-page-layout">
                {page.title && (
                    <h1 className="text-center my-5" data-sb-field-path="title">
                        {page.title}
                    </h1>
                )}
                {topSections.length > 0 && (
                    <div data-sb-field-path="sections">
                        {topSections.map((section, index) => {
                            const Component = getComponent(section.type);
                            if (!Component) {
                                throw new Error(`no component matching the page section's type: ${section.type}`);
                            }
                            return <Component key={index} {...section} data-sb-field-path={`sections.${index}`} />;
                        })}
                    </div>
                )}
                <div className='grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-10 my-16 max-w-screen-md mx-auto'>
                    {authors.map((author, index) => (
                        <div className='group text-center' key={index}>
                            {author.image && <ImageBlock {...author.image} 
                                className="group-hover:shadow-md transition-shadow rounded-full w-40 h-40 mx-auto" />}
                            <h3>{author.firstName} {author.lastName}</h3>
                            <span className="text-gray-500">{author.role}</span>
                        </div>
                    ))}
                </div>
                {bottomSections.length > 0 && (
                    <div data-sb-field-path="sections">
                        {bottomSections.map((section, index) => {
                            const Component = getComponent(section.type);
                            if (!Component) {
                                throw new Error(`no component matching the page section's type: ${section.type}`);
                            }
                            return <Component key={index} {...section} data-sb-field-path={`sections.${index}`} />;
                        })}
                    </div>
                )}
            </main>
        </BaseLayout>
    );
}

First, notice that you display the topSections first and the bottomSections last in your layout.

In the middle, you display the authors in a grid. The authors are received in the props of the layout. You'll be defining this in the next section.

After creating this layout, add it in src/components/layouts/index.tsx:

import PostFeedLayout from './PostFeedLayout';
//...

export {
	...,
    PersonFeedLayout
}

Finally, you need to add it to src/components/components-registry.ts:

const components = {
    //...,
    'PersonFeedLayout': dynamic(() => import('./layouts/PersonFeedLayout'))
};

Add Props

To define the props passed to this layout, first, go to src/utils/data-utils.js and add a new function:

export function getAuthors(objects) {
    return objects.filter((object) => object.type === 'Person');
}

The sourcebit-target-next plugin will use the sourcebit-source-filesystem to read files under content and import them into your Stackbit website.

There are two types of content: pages under the content/pages directory and data under content/data directory. You'll be able to filter out content based on the type field for data content, or the layout field for pages content.

In this case, you're retrieving all authors, which are data content. So, you check if the type field is Person. Please note that, by default, all authors are under content/data/team in JSON files.

Next, you'll use this function to pass the authors as a prop to the layout you created in the previous section. Go to src/utils/static-props-resolvers.js and add the following:

import {
    //...,
    getAuthors
} from './data-utils';

//...

const StaticPropsResolvers = {
    //..,
    PersonFeedLayout: (props, data) => {
        return {
            ...props,
            authors: getAuthors(data.objects)
        };
    }
};

Your Next.js website will resolve the props of the layouts by checking through the StaticPropsResolvers object. The key is the name of the layout and the value is a function that returns an object which will be the props of the layout.

You add a new key for PersonFeedLayout which accepts props and data as parameters. props is the data entered by the user in the UI for the fields you created for the content model earlier. For example, the bottomSections field.

The data is all the data on your website made available by sourcebit-target-next as explained earlier. It is an object that has 3 properties:

  1. objects which is an array of all content files loaded by the sourcebit-source-filesystem plugin.
  2. pages which is an array holding all static page props.
  3. props which is an object with common props for all pages.

In this function, you return all the props as-is and you add the authors prop which will call the getAuthors function you created earlier passing it data.objects.

Add the Authors Page

Finally, you just need to add the Authors page. Create the file content/pages/authors.md with the following content:

---
title: Authors
layout: PersonFeedLayout
topSections:
  - type: CtaSection
    elementId: ''
    colors: colors-a
    backgroundSize: full
    title: Let's do this
    text: >-
      The Stackbit theme is flexible and scalable to every need. It can manage
      any layout and any screen.
    actions:
      - type: Button
        label: Try it now
        url: /
        style: primary
    backgroundImage: null
    styles:
      self:
        height: auto
        width: narrow
        margin:
          - mt-0
          - mb-0
          - ml-0
          - mr-0
        padding:
          - pt-24
          - pb-24
          - pl-4
          - pr-4
        alignItems: center
        justifyContent: center
        flexDirection: col
      title:
        textAlign: left
      text:
        textAlign: left
      actions:
        justifyContent: flex-start
---

This defines the page to use the PersonFeedLayout and adds among its top sections a Call to Action (CTA) section.

If you run your server now:

npm run dev

and go to /authors, you'll be able to see all the authors in your blog.

If you push the changes to the preview branch you'll be able to see your new page in the Stackbit app as well as edit the page fields.

Optionally, you can add a link to the page in the header. To do that, open content/data/config.json and add the new link under primaryLinks in header:

{
	...,
    "header": {
    	...,
        "primaryLinks": [
        	...,
            {
                "type": "Link",
                "label": "Authors",
                "altText": "Authors",
                "url": "/authors"
            }
        ]
    }
}

If you save the changes and view the website in local development, or push the changes to the preview branch to view it on the Stackbit app, you'll see a new link the navigation bar for "Authors".

Conclusion

In this tutorial, you learned how you can set up Stackbit and do some development and customization on it. For more features, be sure to check out Stackbit's documentation for more details.