Content Modeling in Next.js
Learn how to handle different nestable and content type blocks, render rich text, and use story references to manage content globally.
Setup
Copy this reference space, providing the intended structure to follow this guide. Make sure to update the access token.
Alternatively, in the existing space, create a new content type block article
and an “Articles” folder with content. The article content type block should have the following fields:
title
: Textcontent
: Rich text
Learn more about fields in the concept.
Also, create an article-overview
content type block and create it as the root story of the “Articles” folder. This block requires no fields.
Finally, create a featured-articles
nestable block with the following field:
articles
: References
Add a new featured-articles
block to the body
field of the home story and select some articles to be featured.
Fetch and list all articles
Create a new components/ArticleOverview.jsx
file to get all stories from this new content type.
import { getStoryblokApi } from '@/lib/storyblok';
import Link from 'next/link';
export default async function ArticleOverview() {
const storyblokApi = getStoryblokApi();
let articles = await storyblokApi.getAll('cdn/stories', {
version: 'draft',
starts_with: 'articles',
content_type: 'article',
});
return (
<div>
<h1>Articles</h1>
<ul>
{articles.map((article) => (
<li key={article.uuid}>
<Link href={`/${article.full_slug}`}>{article.name}</Link>
</li>
))}
</ul>
</div>
);
}
The starts_with
parameter is being used to fetch stories from the “Articles” folder. The content_type
parameter restricts the results to stories of the content type article
, ensuring that the article_overview
is excluded.
Learn more about parameters and filter queries in the Content Delivery API documentation.
Now, the article overview page shows a list of links to all articles.
Create the article block
Add a new components/Article.jsx
component to render the new article content type.
import { storyblokEditable, StoryblokRichText } from '@storyblok/react/rsc';
const Article = ({ blok }) => {
return (
<div className="article" {...storyblokEditable(blok)}>
<h1>{blok.title}</h1>
<p>
<StoryblokRichText doc={blok.content} />
</p>
</div>
);
};
export default Article;
To render rich text fields, the StoryblokRichText
component provided by the @storyblok/react
module is used.
Learn more about handling rich text in Storyblok in the fields concept and the @storyblok/richtext reference.
When clicking on links present in the article overview page, an article page renders correctly.
Handle referenced stories
In the src/app/[...slug]/page.js
data file, use the resolve_relations
parameter to receive the complete story object for referenced stories.
import { StoryblokStory } from '@storyblok/react/rsc';
import { getStoryblokApi } from '@/lib/storyblok';
export default async function Page({ params }) {
const { slug } = await params;
const fullSlug = slug ? slug.join('/') : 'home';
const storyblokApi = getStoryblokApi();
let { data } = await storyblokApi.get(`cdn/stories/${fullSlug}`, {
version: 'draft',
resolve_relations: 'featured-articles.articles',
});
return (
<div>
<StoryblokStory story={data.story} />
</div>
);
}
Learn more in the references concept documentation.
Next, create a new src/components/FeaturedArticles.jsx
component.
import { storyblokEditable } from '@storyblok/react';
export default function FeaturedArticles({ blok }) {
return (
<section {...storyblokEditable(blok)} className="featured-articles">
<h2>Featured Articles</h2>
<ul>
{blok.articles.map((article) => (
<li key={article.uuid}>
<a href={`/${article.full_slug}`}>{article.name}</a>
</li>
))}
</ul>
</section>
);
}
Now, this component will render links to the featured articles on the home page of the project.
Next Part
Internationalization in Next.jsPrevious Part
Dynamic Routing in Next.js