docs
  1. SCAYLE Resource Center
  2. Developer Guide
  3. Integrations
  4. CMS
  5. Storyblok

Storyblok

Introduction

The SCAYLE Storefront Boilerplate includes a default integration that allows you to use Storyblok as a CMS. It includes various helpers to quickly introduce custom content into a Storefront Boilerplate-based shop application.

The Storefront Boilerplate uses @storyblok/nuxt in the background. For further details consult the Storyblok documentation.

Quick links

Storefront Integration

Local Preview

You can preview your local environment within Storyblok:

Storyblok Local Environment

Product data

To link to your shop data, the Storefront Boilerplate adds fields in Storyblok that you can then fill with your desired categories and products:

Storyblok fields for categories and products

Ready Components

The following components are implemented as part of the Storefront Boilerplate, which means they are available out-of-the-box for all shops that are scaffolded from the Storefront Boilerplate - that is, all SCAYLE shops.

Base Storyblok Components

  • Accordion
  • AccordionEntry
  • Banner
  • BannerLink
  • ClickableImage
  • CmsImage
  • CmsLink
  • CmsText
  • CmsVideo
  • DetailImage
  • Grid
  • GridTile
  • ImageSlider
  • ImageSliderSlide
  • ImageText
  • Page
  • Product
  • ProductSlider
  • ScrollableLinkList
  • SlideShow
  • Story
  • StoryblokLink

Technical Details

The Storyblok integration with Storefront Boilerplate is separated between local development (using storyblok cli) and shop runtime (using @storyblok/nuxt).

Initial development setup

To use Storyblok as your CMS, add the following configuration to your nuxt.config.ts:

export default defineNuxtConfig({
    cms: {
        provider: 'storyblok'
    },
})

The initial setup of Storyblok within Storefront Boilerplate requires the creation of a dedicated local .env.storyblok file. The local .env.storyblok will contain all Storyblok-relevant environment variables necessary to work locally with the Storyblok.

STORYBLOK_PERSONAL_TOKEN=<INSERT-YOUR-TOKEN-HERE>
STORYBLOK_SPACE_ID=<INSERT-YOUR-SPACE-ID-HERE>
export default defineNuxtConfig({
    runtimeConfig: {
        cms: {
            accessToken: '', // Overide: NUXT_PUBLIC_CMS_ACCESS_TOKEN
        },
    },
})

Create a STORYBLOK_PERSONAL_TOKEN

A STORYBLOK_PERSONAL_TOKEN can be created as part of the Storyblok Account Settings.

Source the STORYBLOK_SPACE_ID

The STORYBLOK_SPACE_ID can be found as part of the URL when logged into storyblok.com and accessing the appropriate Storyblok space.

Scripts

As part of the Storefront Boilerplate package.json, some additional scripts are included to interact with Storyblok. These are:

  • storyblok:download
    • Downloads the latest components from the respective Storyblok space using Storyblok CLI
  • storyblok:generate
    • Uses the downloaded components JSON schema and transforms it into TypeScript types (See section "Type Definitions")
  • storyblok:login
    • Authenticates local development environment with Storyblok CLI
  • storyblok:unused
    • Outputs overview of used and unused Storyblok components

While storyblok:download and storyblok:login are directly utilizing the Storyblok CLI, storyblok:generate and storyblok:unused are executing dedicated .cjs scripts.

storyblok:generate

The storyblok:generate script, located at scripts/storyblok-generate.cjs, creates a TypeScript type definition based on the local Storyblok components JSON schema. The JSON schema needs to be downloaded before running this command.

The generated TypeScript type definition will be located at storyblok/types/storyblok.gen.d.ts.

To create the generated type definition, the script uses a custom internal NPM package called storyblok-generate-ts, which provides a configurable transformation function storyblokToTypescript(. This function facilitates the actual transformation of the JSON schema and outputs the type definition based on the passed configuration object, which is pre-configured for usage with Storefront Boilerplate.

storyblok:unused

The storyblok:unused script, located at scripts/storyblok-unused.cjs, creates a list of all unused components of a space by utilizing the Storyblok Management API.

You can find the original script here.

Type Definitions

  • storyblok/types/storyblok.d.ts
    • Manual type definition
  • storyblok/types/storyblok.gen.d.ts
    • Generated type definition

Local Dev

The process to synchronize a Storefront Boilerplate project during local development is identical for both new and existing projects.

Basic Composables and Helpers

To simplify the usage of certain functionalities with Storyblok components, the SCAYLE Storefront Boilerplate includes a few simple reusable composables:

  • storyblok/composables/useCmsAlignment.ts
    • Provides Tailwind-compatible alignment classes to be used with Storyblok components
  • storyblok/composables/useStoryblokImage.ts
    • Provides utilities process and return a sanitized teaser image object to be used with Storyblok components
  • storyblok/composables/useStoryblokMargins.ts
    • Provides Tailwind-compatible margin classes to be used with Storyblok components
  • composables/useCmsListingContent.ts
    • Returns a formatted object for usage with listings containing the CMS content, preListingContent, postListingContent and hasTeaserImage

Shop Runtime

The runtime integration between Storyblok and the SCAYLE Storefront Boilerplate is achieved by using the @storyblok/nuxt module.

The configuration can be extended under the storyblok key as part of the nuxt.config.ts. Refer to the official Storyblok module documentation for more information and configuration options.

The default configuration only sets the STORYBLOK_ACCESS_TOKEN and enables the bridge option. The bridge option is used for integrating with the Nuxt framework and with the Storyblok visual editor.

The integration additionally relies on the @nuxt/image module (See NuxtImage module documentation) to handle images used with Storyblok components.

Deployment Requirements

The @storyblok/nuxt module provides an integration with the Nuxt RuntimeConfig functionality. This means that the NUXT_STORYBLOK_ACCESS_TOKEN can be set during the application's runtime as an environment variable instead of during build time.

Auto-imported components

Storyblok components are auto-imported from the storyblok/ directory at the root of the project and the components are made available throughout the project. Be mindful of component name collisions. If your component in the ~/components directory is named the same as the one inside ~/storyblok there can be issues with the Storyblok auto imported components.

The StoryblokComponent is also auto imported and can be used out-of-the-box.

Fetching content

Storefront Boilerplate provides a simple way to fetch content from Storyblok.

useCMS

As content from Storyblok allows references to data provided by SCAYLE, for example product data, the SCAYLE Storefront Boilerplate features the useCMS composable. This composable internally relies on the storyblok-js-client package to fetch.

useCMS accepts the key argument that will be used as a key for useAsyncData for storing values.

An example usage for getting relevant content might look like the following:

const {
  data, status
} = await useCMSBySlug<SbFooter>('footer', 'global/footer')

useCMS is a file that exposes the following two dedicated composables:

  • useCMSBySlug
    • Wraps async function around useAsyncData and useStoryblokApi composable to fetch Storyblok content by slug using the slug format cdn/stories/${slug}.
  • useCMSByFolder
    • Wraps async function around useAsyncData and useStoryblokApi composable to fetch Storyblok content by folder using the starts_with parameter.

    As the composables useCMSBySlug and useCMSByFolder wrap around useAsyncData, you then have the whole type signature. For more details on all returned data, refer to the Nuxt documentation.
import type { SbFooter } from '~/modules/cms/providers/storyblok/types'
import { useCMSBySlug } from '~/modules/cms/providers/storyblok/composables/useCMS'

const props = defineProps<{
  slug: string
}>()

const { fetchBySlug } = useCMS(`content-page-${props.slug}`)

const { data, error, status } = await useCMSBySlug<SbContentPage>(
  `content-page-${props.slug}`,
  `content/${props.slug}`,
)

While the Nuxt 2-based implementation allowed for Storyblok content to be manually cache-controlled, this feature set is currently not available for the Nuxt 3-based implementation.

Live Preview

To display unpublished changes on the initial load within the Storyblok editor, the access token needs the Preview access level. If the access token has a different access level, unpublished changes will only appear after modifications are made within the editor.

Components

This section offers a detailed overview of various shop areas utilizing Storyblok content, alongside their configuration options. It's essential to review the type definitions to understand the optional values and the expected data types for each configuration option.

Homepage

Component: SlideShow

ParameterDetails
h1String
slidesSbSlide[]
margin_top

String

Accepts ''

Component: Slide

ParameterDetails
imageSbCmsImage | SbVideo
toplineString
headlineString
cta_labelString
cta_urlString
is_darkBoolean
align

String

Accepts 'start'

justify

String

Accepts 'start'

Component: ImageSlider

ParameterDetails
imageSbCmsImage | SbVideo
headlineString
cta_labelString
cta_urlString
slidesSbImageSliderSlide[]
margin_top

String

Accepts ''

Component: ImageSliderSlide

ParameterDetails
imageSbCmsImage | SbVideo
toplineString
headlineString
is_newBoolean
cta_labelString
cta_urlString
item_idString
item_nameString
promotion_idString
promotion_nameString
creative_nameString
creative_slotString

Component: Grid

ParameterDetails
margin_top

String

Accepts ''

is_containeredBoolean
is_containered_desktopBoolean
is_spacedBoolean
columnsSbShopableImage

Component: GridTile

  • Options:
    • headline: accepts a string
    • cta: accepts a string
    • cta_link: accepts a link
ParameterDetails
contentSbShopableImage
headlineString
ctaString
cta_linkSbmultilink


Component: ImageText

ParameterDetails
image

String

Accepts 'start'

imageSbCmsImage[]
toplineString
headlineString
textString
ctaString
cta_linkSbmultilink
justify

String

Accepts 'start'

Component: ProductSlider

ParameterDetails
headlineString
cta_labelString
cta_urlString
product_ids

String

References to SCAYLE products

margin_top

String

Accepts ''

Component: Banner

ParameterDetails
is_activeBoolean
type

String

Accepts ''

bodyString
countdown_untilString
linksSbBannerLink[]
item_idString
item_nameString
promotion_idString
promotion_nameString
creative_nameString
creative_slotString
location_idString
indexString
cta_urlSbmultilink

Component: Story

ParameterDetails
colorString
imageSbasset
labelString
cta_urlString

Component: Footer

ParameterDetails
textRichtext
align_rightBoolean
link_groupsSbLinkGroup[]
text_bottomString
social_mediaSbSocialMediaLink[]

Component: LinkGroup

ParameterDetails
titleString
linksSbLink[]

Component: Link

ParameterDetails
labelString
cta_urlSbmultilink
open_in_new_tabBoolean

Listing Pages

Component: ListingPage

ParameterDetails
teaser_imageSbasset
teaser_image_mobileSbasset
pre_listing_contentSbAccordion | SbAccordionEntry | SbBanner | SbBannerLink | SbClickableImage | SbCmsImage | SbCmsText | SbContentPage | SbDetailImage | SbDoubleColumn | SbFooter | SbGrid | SbGridTile | SbImageSlider | SbImageSliderSlide | SbImageText | SbLink | SbLinkGroup | SbListingPage | SbPage | SbParagraph | SbProduct | SbProductSlider | SbShopableImage | SbSlide | SbSlideShow | SbSocialMediaLink | SbStory | SbTitle | SbVideo
SEO
{
title: string
plugin?: string
og_image?: string
og_title?: string
description?: string
twitter_image?: string
twitter_title?: string
og_description?: string
twitter_description?: string
}
post_listing_contentSbAccordion | SbAccordionEntry | SbBanner | SbBannerLink | SbClickableImage | SbCmsImage | SbCmsText | SbContentPage | SbCustomerServiceInfo | SbDetailImage | SbDoubleColumn | SbFooter | SbGrid | SbGridTile | SbImageSlider | SbImageSliderSlide | SbImageText | SbLink | SbLinkGroup | SbListingPage | SbPage | SbParagraph | SbProduct | SbProductSlider | SbShopableImage | SbSlide | SbSlideShow | SbSocialMediaLink | SbStory | SbTitle | SbVideo

Service Pages

Component: Accordion

  • Options:
    • has_link_list: accepts a boolean
    • entries: accept a list of SbAccordionEntry
    • margin_top: accepts a string
ParameterDetails
has_link_listBoolean
entriesSbAccordionEntry[]
margin_top

String

Accepts ''

Component: AccordionEntry

ParameterDetails
titleString
link_titleString
bodyRichtext

Area: Content Pages

Component: Content Page

ParameterDetails
teaser_imageSbasset
teaser_image_mobileSbasset
headlineString
sublineString
contentSbCmsImage | SbCmsText | SbGrid | SbImageSlider | SbProductSlider | SbSlideShow | SbSocialMediaLink | SbVideo | SbAccordion | SbCustomerServiceInfo | SbDoubleColumn | SbParagraph
SEO
{
title: string
plugin?: string
og_image?: string
og_title?: string
description?: string
twitter_image?: string
twitter_title?: string
og_description?: string
twitter_description?: string
}

All Pages

Component: Video

ParameterDetails
control_colorString
-autoplayBoolean
has_controlsBoolean
is_containeredBoolean
videoSbasset
preview_desktop_imageSbasset
preview_mobile_imageSbasset
loopBoolean
item_idString
item_nameString
promotion_idString
promotion_nameString
creative_nameString
creative_slotString
location_idString
margin_top

String

Accepts ''

Component: ClickableImage

ParameterDetails
imageSbCmsImage[]
cta_urlSbmultilink
item_idString
item_nameString
promotion_idString
promotion_nameString
creative_nameString
creative_slotString
location_idString
margin_top

String

Accepts ''

Component: CmsImage

ParameterDetails
desktop_imageSbasset
mobile_imageSbasset
item_idString
item_nameString
promotion_idString
promotion_nameString
creative_nameString
creative_slotString
location_idString
indexString

Component: CmsText

ParameterDetails
bodyRichtext

Component: DoubleColumn

ParameterDetails
column_rightSbAccordion | SbAccordionEntry | SbBanner | SbBannerLink | SbClickableImage | SbCmsImage | SbCmsText | SbContentPage | SbDetailImage | SbDoubleColumn | SbFooter | SbGrid | SbGridTile | SbImageSlider | SbImageSliderSlide | SbImageText | SbLink | SbLinkGroup | SbListingPage | SbPage | SbParagraph | SbProduct | SbProductSlider | SbShopableImage | SbSlide | SbSlideShow | SbSocialMediaLink | SbStory | SbTitle | SbVideo
column_leftSbAccordion | SbAccordionEntry | SbBanner | SbBannerLink | SbClickableImage | SbCmsImage | SbCmsText | SbContentPage | SbCustomerServiceInfo | SbDetailImage | SbDoubleColumn | SbFooter | SbGrid | SbGridTile | SbImageSlider | SbImageSliderSlide | SbImageText | SbLink | SbLinkGroup | SbListingPage | SbPage | SbParagraph | SbProduct | SbProductSlider | SbShopableImage | SbSlide | SbSlideShow | SbSocialMediaLink | SbStory | SbTitle | SbVideo
margin_top

String

Accepts ''

Component: Paragraph

ParameterDetails
headlineString
ctaSbmultilink
bodyRichtext
sub_titleString
imageSbmultiasset