Tutorial: BCMS Widgets - Reusable structured content - everything you need to know
Published: 2024-02-28 15:49:07

In modern web development, separations of logic have been a real trend and industry standard. This has led to the invention of the [Microservices Architecture](https://microservices.io/) and has given way for component adaptation in modern frontend development.

With this in mind, frontend tools have constantly looked for ways to blend in by introducing patterns and features that help you separate logic and build components that you can reuse in different places in your application.

In this tutorial, I’ll be focusing on widgets, a BCMS feature that helps to separate logic and also to reuse a group of content in an application dynamically. You’ll learn in-depth what Widgets are, how they help you to organize and reuse your content, and how you can use them.

While a large knowledge of BCMS is not required, I will advise you to have prior knowledge to fully get the most out of this article and be able to follow seamlessly.

## Introduction to BCMS Widgets

[Widgets](https://docs.thebcms.com/inside-bcms/widgets) in BCMS are reusable building blocks used inside the [entry's content area](https://docs.thebcms.com/inside-bcms/entries).

To better understand what widgets are, you will first need to understand what Groups in BCMS are and look at the differences between widgets and groups.

Groups in BCMS are reusable building blocks that are made of multiple [properties](https://docs.thebcms.com/inside-bcms/properties). Groups can be included in any template, widget, or even other groups.

### Now what is the difference between a group and a widget?

Imagine you have a blog website, like a personal travel blog.

And in the middle of your "My Trip to Japan" article, you want to have an image gallery, with a title, description, and list of images. Each image in the gallery will have a title and description of the image.

Something like this:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hv6pk8xj05c2b9v2hv27.png)

To achieve that in BCMS, you will create: A group, called: Image in Gallery, which will contain:

- "Image" - media input
- "Title" - string input
- "Description" - string or rich text input.

Which will be this block here:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hswnxtu6gaaori054tew.png)

So, you will group your three inputs into a group called "Image in gallery". Then, you can create a widget, with the following inputs:

- "Title" - string input
- "Description" - string or rich text input
- "Images" - group pointer (array) -> pointing to an Image in the gallery.

With that in mind, a new, more detailed definition of groups and widgets can be reached.

A group is just a way to put multiple inputs together, so you can reuse them several times (like in this example, with multiple images in the gallery). And groups are like smaller pieces of the application.

Widgets on the other hand are sections of the page, these are bigger blocks than groups, which you can use in the middle of content.

## Use cases for BCMS widgets

BCMS widgets can be used in different places in your content. Here are some examples of widgets you can use in your content

- Image Gallery
- A Basic Image And Text Widget


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5ohskzdcgsdb28947tl8.png)

An Overview of how a template of a text with an image widget looks like.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iqqshvbdlyoqq21fdavq.png)

And on the website, it looks very simple the way you want it.

- Testimonial(Review) Widget.
- Newsletter subscription.
- Related Articles
- Job Listing

Now Let’s go ahead to create a “Recent Blog Posts” widget.

## Creating BCMS Widgets

I will create a “Recent Blog Posts” widget that will link to 3 New blog posts. To do that I will need to have a Blog Post template.

To create a widget I’ll log in to a running BCMS instance. You can get a running BCMS instance by signing up to [BCMS Cloud](https://cloud.thebcms.com/) or using the [self-hosted version](https://docs.thebcms.com/install/locally).

Go into your dashboard and create a new widget named “New Blog Posts” or whatever you would like to call it, but for this article I will call it “New Blog Posts”.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5z35uq26dvt9wz9djjrd.png)

### What are the properties needed in this widget?

A widget like this will typically be in the middle of a home page or at the end of an article so that it can direct users to newly published articles for them to continue reading as shown in the below image.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ng2gx5elo8ysu0evn6f.png)

So the properties needed for this widget are the Title at the top and then an entry pointer to recent articles.

Go ahead now and create a property named title which will be Required.

And now for the entry pointer, you will need a blog post template. So now go ahead to create a simple blog post template. To keep it simple these are the properties that the template will contain:

- Title (Default)
- Slug (Default)
- Cover Image - Media
- Article Body - Rich text


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gsql38e4vbg5vb89d94p.png)

Let’s go back to the widget and create an entry pointer that will lead to this Blog Post template. I’ll Make it an array so I can link multiple Blog Posts.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9vu3axwapohodc0i0pbe.png)

With that done, the widget is successfully created. Now let's put this widget into use.

## Using the BCMS widget in an entry

Unlike templates, where you can create an entry based on it, a widget doesn’t act like that. A widget is not standalone rather you use it in your templates. So to use this widget you’ll need a template where you can use this widget.

So, the next thing to do is to create a simple Home Page Template and after that, you’ll be able to create a blog post. And then you will create a home page entry where you’ll use the widget to link to your newly created Blog post.

Let’s see how that works in action.

### Creating a Home Page template

The first step is to create a home page template where you can use the widget. To create a template log into your dashboard click on the templates tab and create a new template named “Home page”.

Since you need it to be simple, you won’t add additional properties to it other than the defaults and you’ll also toggle on The “Single Entry” Option.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/153tnp0vnk5v6gorbazn.png)

### Creating A Blog Post

To create a blog post, navigate to the Entries section of your dashboard, click on Blog Post(Or whatever you named it), and then click on Add New Blog Post in the top right.

You can put dummy data in there, the purpose is to have a blog post you can link to your widget.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q18ulfgc2gry0i50ttvg.png)

### Using BCMS Widget in the Home Page Entry

So, here comes the time when you finally put the widget to use. As explained earlier, you want this widget to show up on your home page, in between home page contents so it can link to recent job openings.

I will now create an entry in the home page section.

To use a widget, click on the Textbox below the title box and type a forward slash “/”, which will display a list of available properties you can use there. Scroll to the bottom and you’ll see the widget displayed there. You can now click on it and link it to your previously created blog post.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1qox4274j6wmq0ixot0a.gif)

With that, the BCMS widget is successfully created and used on the CMS side. Now it’s time to focus on the code side: how you can use this widget from BCMS to your frontend application and display it.

## Pulling BCMS data to frontend

The moment has come to pull our BCMS data to the frontend. For this tutorial, I am going to use Nuxt.js as the frontend framework, but you can follow along with either [Next.js](https://docs.thebcms.com/integrations/next-js) or [Gatsby](https://docs.thebcms.com/integrations/gatsby-js) which we BCMS only support for now.

Visit the [Nuxt BCMS documentation](https://docs.thebcms.com/integrations/nuxt-js) to learn how to create a Nuxt project.

Heads Up: Before creating the Project, go to your key manager in administration under your dashboard to create an API key. You will need this key to connect to your Nuxt project when creating it. If you're asked to log in when trying to connect to your bcms instance, run `bcms --login true`to log your terminal into your instance.

After creating your application, you will have default files in the pages folder, you should have a look at them to see what is happening and how data is being fetched from the instance. But I will clean up the pages folder, start from scratch, and use Vue syntax instead of JSX.

BCMS provides [query functions](https://docs.thebcms.com/integrations/nuxt-js#getting-data-from-bcms-in-a-nuxt-page) that help us get data.

```
const { data } = useAsyncData(async (ctx) => {
  const blog = (await ctx?.$bcms.entry.get({
    template: 'blog',
    entry: 'how-to-connect-bcms-and-nuxtjs',
  })) as BlogEntry;
  return { blog }
});

```
In this case, I need to get the homepage data since that is where I linked the widget. Under the pages folder, create an index.vue. 7

```
<template>
  <p>Hello world</p>
</template>

<script lang="ts" setup></script>

<style></style>

```
Under the script section, you can now use our query method to get the home page entry so: 

```
// This is a type BCMS automatically generated for us when we created the project.
// It is generated to model the way we structured our home page template
import { HomePageEntry } from '~~/bcms/types';


const { data } = useAsyncData(async (ctx) => {
  const homepage = (await ctx?.$bcms.entry.get({
		// You can use the name of the template and entires or as i did here, it's ID
    template: '65a1a3b2a07a1732302f8db5',
    entry: "home"
  })) as HomePageEntry;
  return { homepage }
});

console.log(data.value?.homepage);

```
Check your console and you should see the home page data logged. With that done, you’ve successfully pulled the data to your home page, on your template you can now use this data however you want.

But since this article is about widgets I will focus on only widgets here and how you can render them.

## Rendering BCMS Widgets with ContentManager

Navigate to “content” under the data in your console, you will see the new_blog_posts widget and the Blog(s) you linked to it.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l7sn2j7k4zix08ig9b0n.png)

From the above picture, you can see the widget returned and the Blog Post I linked to it being returned as well.

So how to render these and make them appear in the same place you put them when creating your entry? You do not render them in the Index.vue page, rather you will create a widget file for each of the widgets you have in your application which will handle the designing of the widget and how it should appear, and after that, you will create a ContentManager component and will use it to display the widgets, and this component is what displays the right widgets at the right place.

Create a new folder under the root folder named Components and create another folder named “Widgets” and then a new file under widgets named NewBlogPosts.vue or the name of your widget.

```
<template>
  <h1>{{ data.title }}</h1>
</template>

<script setup lang="ts">
import { BCMSEntryContentParsedItem } from '@becomes/cms-client/types';
import { PropType } from 'vue';
//This is a Bcms Image component which you can use to render your images
import { BCMSImage } from '../../bcms-components';
import { NewBlogPostsWidget } from '../../bcms/types';
const props = defineProps({
  data: {
    type: Object as PropType<NewBlogPostsWidget>,
    required: true,
  },
});

</script>

```
You can see that this widget expects a data property. This data property contains the values you added to the widget which are the title and the blog posts you linked as displayed in the console. This is the reason I can access the title in the h1 component.


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0h2tnmzxq7s06hl47ucj.png)

You can now go ahead to style this component however you want, checking the console to view possible properties you can get and how you can make the linked blog posts a grid. But I won’t go into that in this tutorial, I will stick to getting the data and being able to display them.

The widget alone won’t work just yet. Now what you need is the content manager component that accepts all widgets and uses BCMS internal ContentManager component to display those widgets in the right way along with a method to parse internal links.

First, I will make A ContentManger.vue file under the component folder and then set up all I need to render the widget.

```
<template>
  <BCMSContentManager
    ref="managerDOM"
    :items="item"
    :widget-components="widgetComponents"
    @vue:mounted="parseInternalLinks"
  />
</template>

<script setup lang="ts">
import { BCMSPropRichTextDataParsed } from '@becomes/cms-client/types';
import { PropType } from 'vue';
import { BCMSContentManager } from '~~/bcms-components';
import NewBlogPosts from '~~/components/widgets/NewBlogPosts.vue';

defineProps({
  item: {
    type: Object as PropType<BCMSPropRichTextDataParsed>,
    required: true,
  },
  widgetComponents: {
    type: Object,
    required: false,
    default: () => {
      return {
        new_blog_posts: NewBlogPosts,
      };
    },
  },
});

const managerDOM = ref<any>();

const parseInternalLinks = () => {
  if (managerDOM.value.$el) {
    setTimeout(() => {
      const links = managerDOM.value.$el.querySelectorAll('a');

      links.forEach((link: HTMLAnchorElement) => {
        const href = link.getAttribute('href');

        if (href && href.startsWith('/')) {
          link.target = '_self';
          link.addEventListener('click', (event) => {
            event.preventDefault();

            navigateTo(href);
          });
        }
      });
    }, 0);
  }
};
</script>

```
The ContentManger component expects two props, which are

- item - This is the array of all the widgets.
- widgetComponents - The Widget.vue file for all the widgets you will be handling. As you can see you can fall back to a default, that is if you have just one widget as it is in this case

So now, you can use this ContentManager.vue component in index.vue file.

```
<template>
  <h1>Hello world</h1>
  // I wrapped this in a client only Nuxt component to render it only on the client
	// And not on the server.
  <ClientOnly>
    <ContentManager :item="homepageData?.content.en" v-if="homepageData" />
  </ClientOnly>
</template>

```
In the script tag, you will create a new variable homepage which will hold homepage data.

```
<script lang="ts" setup>
import { HomePageEntry } from '~~/bcms/types';

const { data } = useAsyncData(async (ctx) => {
  const homepage = (await ctx?.$bcms.entry.get({
    template: '65a1a3b2a07a1732302f8db5',
    entry: "home"
  })) as HomePageEntry;
  return { homepage }
});

const homepageData = data.value?.homepage;
</script>

```
You can check your browser now and see that the title is being displayed. Take note that this title is in your NewBlogPosts.vue page.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/om0ol6c5p0qv39t2s96f.png)

At this point, you can go ahead to design the NewBlogPosts.vue component to make it look good and display the blogs linked in a grid manner. I won’t do all that in this article because the main focus is to design the widget on the dashboard, get it in the frontend, and design the component to handle it and you have achieved that in this article.

## Conclusion

From this tutorial, you’ve seen the use cases for BCMS widgets, and how to use them on your dashboard and frontend. ComponentManager highlights the importance of managing widgets effectively, it gives room to design components for all the widgets and allows you to use just the ContentManager.vue file in the index.html and it will display all your widgets.

This is the standard that BCMS employs and encourages you to use as it is the cleanest approach possible currently.

### Next Steps

As I mentioned earlier, you can now go ahead to design the widget component and make it look really good.

In this tutorial, I used a New Blog Post widget to show practical ways to use a widget, but I like I explained earlier, this is not the only thing you can build with widgets. The possibilities are endless.

I encourage you to dive into our [Starters](https://github.com/bcms/starters/tree/master) folder on Github to explore different ways we use widgets in our applications. Do give us a star on [Github](https://github.com/bcms/cms) to support us.

To start your BCMS journey and create applications, sign up for [BCMS Cloud](https://cloud.thebcms.com/).