How to add editable blocks to custom components in vue 3

Hi,
I’m trying to make my custom components editable blocks so they can be edited in the visual editor but i cant find any documentation for this.

Hello @behzad,

Welcome to the Builder.io forum.

You can find assistance in the following articles:

  1. Builder.io Documentation on Custom Components with Children: Custom Components with Children
  2. Vue.js Guide on Components and Slots: Vue.js Components and Slots

Thanks for replying, but there is no vue documentation on this page, all of the docs and tutorials on the forum are written in react.

Hello @behzad,

Most of our documents are currently tailored for React, and we’re actively working on updating our documentation to encompass other tech stacks. Your feedback is greatly appreciated.

In the interim, if you’re using a custom component in Vue, you can refer to the documents shared earlier. Additionally, you can find an example of using slots on our GitHub repository.

Feel free to explore these resources, and if you have any further questions or suggestions, we’re here to assist.

Thanks,

Thanks again for replying,
This vue repository was great and helped me a lot, but the main problem i have is that i cant edit the text and image elements in my custom components like the builder elements. is there any way to make them like the builder.io blocks and not only a text input?

Hello @behzad,

As of now, using child blocks in custom components in Vue is not currently supported. However, I can provide you with a general example of how you might use child blocks in custom components in Vue 3.

Let’s assume you have a custom component named ParentComponent that can contain child components. Here’s a basic example:

<!-- ParentComponent.vue -->
<template>
  <div>
    <h1>Parent Component</h1>
    <!-- Child components will be rendered here -->
    <div class="child-components">
      <slot></slot>
    </div>
  </div>
</template>

<script>
export default {
  name: 'ParentComponent',
};
</script>

In this example, the ParentComponent has a <slot> where child components can be inserted. Now, let’s create a child component:

<!-- ChildComponent.vue -->
<template>
  <div class="child-component">
    <h2>Child Component</h2>
    <!-- Your child component content goes here -->
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: 'ChildComponent',
};
</script>

Now, you can use these components in another Vue file:

<!-- App.vue -->
<template>
  <div id="app">
    <ParentComponent>
      <!-- Child components go here -->
      <ChildComponent>
        <!-- Content of the first child component -->
        <p>Content of the first child component</p>
      </ChildComponent>

      <ChildComponent>
        <!-- Content of the second child component -->
        <p>Content of the second child component</p>
      </ChildComponent>
    </ParentComponent>
  </div>
</template>

<script>
import ParentComponent from './components/ParentComponent.vue';
import ChildComponent from './components/ChildComponent.vue';

export default {
  components: {
    ParentComponent,
    ChildComponent,
  },
};
</script>

I think you misunderstand me, let me show you the problem with a picture:

in the picture the first block is inserted from builder.io template and text elements and images are editable, but the second block is a custom component and nothing can be edited even the text elements.

Hello @behzad,

I’ve got your point, to clarify further, you will create a parent component that will use child components which will be basically the default type of builder sdk elements utilizing defaultChildren

Add <slot></slot> wherever you want your children to be. For more details, visit the Vue document on Slots.

Example:

// Register your Builder components
const REGISTERED_COMPONENTS = [
  {
    component: HelloWorldComponent,
    name: 'Hello World',
    canHaveChildren: true,
    inputs: [
      {
        name: 'text',
        type: 'string',
        defaultValue: 'Hello World',
      },
    ],
    defaultChildren: [
      { 
        '@type': '@builder.io/sdk:Element',
        component: { name: 'Text', options: { text: 'I am child text block!' } }
      }
    ],
  },
];

HelloWorld.vue

<template>
  <div class="hello-world">
    <div class="text">Hello {{ text }}!</div>
    <slot></slot>
  </div>
</template>

<script>
export default {
  props: {
    text: {
      type: String,
      default: 'world',
    },
  },
};
</script>

<style scoped>
.hello-world {
  display: flex;
  flex-direction: column;
}
.text {
  padding: 50px;
}
</style>

okay so for example we cant edit the vue logo image that is coming from the parent component?

@behzad Yes, you can register the logo as a custom component with a default value using .

this is my custom component that im importing and i have zero control on the elements inside the component expect i can make the props and only pass a value to them and cant even change the pictures inside my components, so what problem builder.io is solving when i cant use my custom components with ease? i mean when i import a template from figma i have full control on every element on it so why not in custom components?

<script setup lang="ts">
const props = defineProps<{
  title: string
  description: string
  description2: string
}>()
</script>

<template>
  <div class="services-view top-services bg-light-gray py-lg-5">
    <div class="container py-5">
      <div class="row col-12 px-0 mx-auto">
        <div class="col-lg-6 px-0 px-lg-3">
          <div class="service d-block p-4 p-lg-5 text-center bg-white text-dark-blue mb-3">
            <span class="text-semi-bold my-0">Pricing List</span>

            <h2 class="fs-32 mt-1">{{ props.title }}</h2>

            <p class="fs-18">
              {{ props.description }}
            </p>

            <a
              class="btn-primary-red text-white mx-auto w-max-content px-5 py-2 mt-5"
              href="https://dashboard.1gbits.com/deploy/dedicated"
              target="_blank"
              title="1Gbits all dedicated servers listing"
              >View All</a
            >
          </div>
        </div>

        <div class="col-lg-6 px-0 px-lg-3">
          <div class="service d-block p-4 p-lg-5 text-center bg-white text-dark-blue mb-3">
            <span class="text-semi-bold my-0">Pricing List</span>

            <h2 class="fs-32 mt-1">1Gbits Virtual Private Servers Prices</h2>

            <p class="fs-18">
              {{ props.description2 }}
            </p>

            <a
              class="btn-primary-red text-white mx-auto w-max-content px-5 py-2 mt-5"
              href="https://dashboard.1gbits.com/deploy/vps"
              target="_blank"
              title="1Gbits Virtual Private Servers Prices"
              >View All</a
            >
          </div>
        </div>

        <slot></slot>
      </div>
    </div>
  </div>
</template>

It looks like the builder vue sdk doesn’t support the defineProps macro that vue uses for typescript. Currently this is the only blocker keeping me from using builder. For clarification-

These two work:

<script lang="ts">
export default {
  props: {
    heading: {
      type: String,
      required: true,
    },
  },
}
</script>

OR

<script lang="ts" setup>
defineProps(['heading'])
</script>

This does not:

<script lang="ts" setup>
 defineProps<{
   heading: string
 }>()
</script>

Hello @faz,

The Builder.io Vue SDK currently does not fully support the defineProps macro that Vue uses for TypeScript. Until this feature is supported by the Builder.io Vue SDK, you might need to stick with one of the two approaches you mentioned. Alternatively, you can submit feature requests at Builder.io Ideas.

Thanks, I have added this here: Support defineProps for TS in vue 3 sdk | Builder.io Ideas