⚠️Draft Content

Storyblok Raises $80M Series C - Read News

What’s the True Total Price of Enterprise CMS? Find out here.

Skip to main content

Create Custom Components in Storyblok and Astro

Try Storyblok

Storyblok is the first headless CMS that works for developers & marketers alike.

Let’s take it one step further in this part by exploring component schemas in Storyblok. We’ll learn how to modify existing components, create entirely new ones from scratch and, of course, integrate all of these changes into our Astro frontend.

Live demo:

In a hurry? Check out the source code on GitHub and take a look at the live version on Netlify.

Requirements

This tutorial is part 4 of the Ultimate Tutorial Series for Astro. We recommend that you follow the previous tutorials before starting this one.

Changing Existing Components

Adding an Image Field to the Feature Component

First of all, let’s extend one of the existing components that were created by Storyblok for us: the Feature component. Right now, the Feature components look a little bit bland, don’t they? Adding an image to them would certainly spice things up a little bit.

To modify it right from the Visual Editor, go to the Home story and click on one of the Feature components, which exist as nested blocks in the Grid component. To edit the schema, click on the Block Library button at the top {1}.

Accessing the block schema from the Visual Editor
1

Accessing the block schema from the Visual Editor

Now you immediately start typing. Let’s enter the image as our field name. Now you can click on the newly created field. In this menu, you want to set the Field type to Asset {1} and then choose the file type Images {2}.

Creating an image field
1
2

Creating an image field

And that’s that! After closing the Block Library, you’ll see the image field, providing the possibility to upload an asset. Go ahead and upload some images for the three instances of the Feature component. Of course, they won’t show up in the frontend just yet, so let’s take care of that next.

Showing the Image Field in Astro

In order to render the images properly in Astro, we have to figure out what exactly is provided by Content Delivery API after the changes to our component schema.

Open JSON data
1
2

Open JSON data

If you search for the term feature now, you’ll find the image field and all of the data it provides {1}. For now, all that we need are the filename {2} and the alt {3} values.

Getting the right properties from the Draft JSON
1
2
3

Getting the right properties from the Draft JSON

Perfect. Let’s use those in Astro by updating the storyblok/Feature.astro component:

storyblok/Feature.astro
        
      ---
import { storyblokEditable } from '@storyblok/astro'

const { blok } = Astro.props
---

<div
  {...storyblokEditable(blok)}
  class="w-full bg-[#f7f6fd] rounded-[5px] text-center overflow-hidden"
>
  <img
    src={blok.image.filename}
    alt={blok.image.alt}
    class="w-full h-48 xl:h-72 object-cover"
  />
  <div class="px-12 py-6">
    <h3 class="text-2xl text-[#1d243d] font-bold">
      {blok.name}
    </h3>
  </div>
</div>
    

What’s happening here? The blok object contains all of the information that we need, so the image field and its nested properties filename and alt are easily accessible. In Astro, we can then very easily add these values to any HTML tag, in this case an img.

That already looks much better, doesn’t it?

Refined feature components with images

Refined feature components with images

hint:

Make sure to check out the Storyblok Image Service to optimize your images on the fly.

Creating New Components

Having successfully modified an existing component, let’s now create a completely new block from scratch. Something that our website could really need is a nice-looking hero component, wouldn’t you agree?

Creating a Hero Component

Before creating the schema for this new block, let’s first of all consider what we would like it to look like and what options we want to provide. I would say that a headline, a subheadline and a background_image field would be a great place to start. However, let’s kick it up a notch and provide the option to make this hero component use the full width of the screen.

First, go to the Block Library {1} and create a New Block {2}.

Creating a new block in the Block Library
1
2

Creating a new block in the Block Library

It should be a Nested block {1} with the name hero {2}.

Creating a new nested block
1
2

Creating a new nested block

Now we can create our first three fields:

  • headline: field type Text
  • subheadline: field type Text
  • background_image: field type Image

The required steps for this are exactly the same as we have taken to add an image field to the Feature component earlier in this tutorial.

Once these fields are ready, we can create the layout field to make it possible to choose between two different layouts. Let’s add the field and choose Single-Option as its type {1}.

Creating a single-option field
1

Creating a single-option field

Let's add two key-value pairs which represent the possible choices {1}, hide the empty option {2}, and set the default value to constrained {3}:

Defining the layout options for the hero component
1
2
3

Defining the layout options for the hero component

Finally, save the component and add it to our Home story, right above the Teaser. You can already add some sample content to the fields. Of course, nothing will be shown in our frontend just yet. So let’s take care of that next, shall we?

Rendering the Hero Component in Astro

All we have to do is create a new storyblok/Hero.astro component with the following content:

storyblok/Hero.astro
        
      ---
import { storyblokEditable } from '@storyblok/astro'

const { blok } = Astro.props
let dynamicHeroClass = blok.layout === 'constrained' ? 'container mx-auto' : ''
---

<div
  {...storyblokEditable(blok)}
  class={`${dynamicHeroClass} min-h-[500px] relative flex items-end justify-center my-6 rounded-[5px] overflow-hidden`}
>
  <div
    class="relative z-10 w-full text-center bg-gradient-to-t from-black/70 via-black/50 to-transparent py-6"
  >
    <h1 class="text-6xl text-white font-bold mb-3">
      {blok.headline}
    </h1>
    <h2 class="text-4xl text-white font-light">
      {blok.subheadline}
    </h2>
  </div>
  <img
    src={blok.background_image.filename}
    alt={blok.background_image.alt}
    class="absolute top-0 left-0 z-0 w-full h-full object-cover"
  />
</div>
    

At this point, you should be familiar with most of the code. The only novelty is that we create a computed property dynamicHeroClass to determine which classes should be used depending on the value we get from the layout field we created. This computed property is then added to the class using Template literals.

Next, make sure to register the component in the Storyblok integration in astro.config.mjs.

astro.config.mjs
        
      export default defineConfig({
  integrations: [
    storyblok({
      accessToken: env.STORYBLOK_TOKEN,
      components: {
        page: 'storyblok/Page',
        feature: 'storyblok/Feature',
        grid: 'storyblok/Grid',
        teaser: 'storyblok/Teaser',
+        hero: 'storyblok/Hero',
      },
    }),
    tailwind(),
  ],
})
    

If you refresh your Home story in the Visual Editor now, you’ll not only see the Hero component in all its glory – you can also change the layout and save, it will update accordingly!

The hero component rendered successfully

The Hero component rendered successfully

Wrapping up

Congratulations, when you reached this point you have successfully adapted the schema of existing components, created new components from scratch and incorporated all of the required code changes in your Astro project! Great work!

Next Part:

Continue reading and learn how to Render Blog Articles in Storyblok and Astro

Author

Dipankar Maikap

Dipankar Maikap

Dipankar is a seasoned Developer Relations Engineer at Storyblok, with a specialization in frontend development. His expertise spans across various JavaScript frameworks such as Astro, Next.js, and Remix. Passionate about web development and JavaScript, he remains at the forefront of the ever-evolving tech landscape, continually exploring new technologies and sharing insights with the community.