Vue: nesting components within components

Looking for a clever solution to create a nested component system with efficient rendering? Check out the code snippet below:

custom-tab.vue (child component)

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

<script>
    export default {
        name: 'CustomTab',
        props: ['title']
    }
</script>

custom-tabs.vue (container component)

<template>
    <div class="custom-tabs-switchers">
        <b
            v-for="(tab, index) in tabs"
            :key="`tab-${index}`"
        >
            {{ tab.componentInstance.props.title }}
        </b>
    </div>
    <div class="custom-tabs-contents">
        <div class="custom-tabs-contents-item"
            v-for="(tab, index) in tabs"
            :key="`tab-content-${index}`"
        >
            <!-- HOW TO DISPLAY TAB CONTENT HERE??? -->
        </div>
    </div>
</template>
<script>
    export default {
        name: 'CustomTabs',
        computed () {
            tabs () {
                return this.$slots.default
            }
        }
    }
</script>

example-page.vue (component with usage example)

<template>
    <custom-tabs>
        <custom-tab title="first tab"><p>Content of Tab #1</p></custom-tab>
        <custom-tab title="second tab"><p>Content of Tab #2</p></custom-tab>
        <custom-tab title="third tab"><p>Content of Tab #3</p></custom-tab>
    </custom-tabs>
</template>

Answer №1

The secret to finding a solution is utilizing the render function of the component (https://v2.vuejs.org/v2/guide/render-function.html) in order to add some personalization. Here's an example:

export default {
  name: 'Tabs',
  render: function (createElement) {
    const buttons = []
    const tabs = []
    const children = this.$slots.default // using shortcut

    for (let i = 0; i < children.length; i++) {
      buttons.push(createElement(
        'button',
        children[i].componentOptions.propsData.title
      ))
      tabs.push(createElement(
        'div',
        {
          class: i === 0 ? 'active tab' : 'tab',
          attrs: {
            id: `tab-${i}`
          }
        },
        children[i].componentOptions.children
      ))
    }
    const buttonsContainer = createElement('div', { class: 'buttons' }, buttons)
    const tabsContainer = createElement('div', tabs)

    const root = createElement('div', { class: 'tabs' }, [buttonsContainer, tabsContainer])
    return root
  }
}

I'm uncertain about the VNode API (

children[i].componentOptions.propsData.title
-- does it work correctly?) but from my own experience, the solution works and seems to be the right approach.

Cheers!

Answer №2

In order to render the contents of the slot, you do not need to use v-for.

Vue.component('Tabs', {
  template: `
    <div class="tab-container">
      <slot></slot>
    </div>
  `
})

Vue.component('Tab', {
  template: `
    <div class="tab">
      <strong>{{title}}</strong>
      <slot></slot>
    </div>
  `,
  
  props: ['title']
})

new Vue().$mount('#app');
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <tabs>
    <tab title="tab 1">
      <p>Tab #1 content</p>
    </tab>
    <tab title="tab 2">
      <p>Tab #2 content</p>
    </tab>
    <tab title="tab 3">
      <p>Tab #3 content</p>
    </tab>
  </tabs>
</div>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using jQuery to delay hiding for 2 seconds

Hey there! I'm facing an issue with my code. The function is supposed to make #aboutPopOut slide to the left, and then after a 2-second delay, fade out the fadescreen by hiding it. The sliding part works fine, but the waiting and hiding do not seem to ...

Accessing public static files in Express by using the routes folder

I'm currently facing an issue with accessing a static file named 'home.html' located in the public directory of my app's architecture: public home.html routes index.js views myapp.js In myapp.js: var express = require('ex ...

Guide to building a customized route using Nuxt

Typically, Nuxt automatically creates a route for each page located in the pages directory. What I would like to achieve is that when a user navigates to a specific page such as project.local/id/ec29cjsa5fas512ik, they are directed to a page template and ...

Sorts through nested arrays to uncover distinctive product assortments

Currently, I am in the process of developing a website using Next.js and Shopify. My objective is to create a page that displays all collections matching a specific productType. To achieve this, I have been exploring ways to extract this data from the Gra ...

Reset the text input field when the dropdown menu is set to 'no/other'

CURRENT: Choosing from a dropdown menu with options 'Yes' or 'No'. If 'Yes' is chosen: Display additional dropdowns/inputs for entry If 'No' is chosen: Conceal additional dropdowns/inputs WANT: I am looking to imp ...

Internet Explorer terminates AJAX requests

When I send a request to the server using Ajax and JQuery, it returns more than 2000 records (approximately 16,000 records). In Google Chrome, the call is executed although it takes about 40 seconds. However, in Internet Explorer 11, the execution gets ca ...

Experiencing a [$compile:multidir] error when attempting to implement a multiselect dropdown with Angular.js

I encountered an issue when utilizing a multi-select drop-down list in Angular.js. Error: angularjs.js:107 Error: [$compile:multidir] http://errors.angularjs.org/1.4.6/$compile/multidir?p0=ngDropdownMultiselec…22%20checkboxes%3D%22tr ...

Encountering an issue while trying to set up a fresh react application

Issue encountered when trying to start a new React project ...

The received URL from the POST request in React is now being opened

After completing an API call, I successfully received the correct response in my console. Is there a way to redirect my React app from the local host to the URL provided (in this case, the one labeled GatewayUrl under data)? Any assistance would be greatly ...

Guide on choosing a specific div element from a different page using AJAX

I have a Social Media platform with posts, and I am trying to display the newest ones using JavaScript (JS) and AJAX. I attempted to reload my page using AJAX and insert it into a div element, but now the entire website is loading within that div element, ...

Is it possible to utilize various return values generated by a regex?

Working on a project where I am utilizing regex to extract links from a Google Calendar XML feed. The links appear in the following format: <a href="http://www.drsketchysdublin.com/event-registration/?ee=11">http://www.drsketchysdublin.com/event-reg ...

Having trouble getting the .toggle() function with classList to work on one element, despite working fine on others

I've been struggling to apply a class to an HTML element when I click on another element of the page. Despite numerous attempts, it just doesn't seem to work for me. Let's take a look at my code: HTML Code: <div class="container&qu ...

Tips for creating a high-performing algorithm to locate a specific word within a JSON file

I am in the process of creating a word game that involves users typing letters on a board to form meaningful words. If the typed word matches any word in a JSON file, the user earns a point. I have successfully implemented the basic functionalities of the ...

What is the best way to conceal a parent element with jquery?

Let's say we have the following HTML structure: <li class="fooli"> <a class="foo" href="javascript:foo(this);">anchor</a> </li> <li class="fooli"> <a class="foo" href="javascript:foo(this);">anchor</a> ...

Assign characteristics to the button, however it will only activate after being clicked twice

The button I created with some bootstrap attributes is not working properly on the first click. To resolve this, I initially called the function in onload and then again on the button click. However, I am now unable to do so and am seeking alternative solu ...

How to align two <select> elements side by side using Bootstrap

The issue I am encountering is that these two select elements within the same control-group are being displayed vertically when I want them to be displayed horizontally. I attempted using inline-block in CSS, but there are other <div> elements with ...

Unique: "Unique One-Step Deviation in Date Comparison"

A Little Background Information: I am working with data points that span from the current day to 5 days ahead, in 3-hour intervals (such as 10pm, 1am, 4am, 7am...). My goal is to organize these data points into arrays sorted by date, with each array repre ...

Having trouble uploading several files with Multer functionality?

I've encountered an issue with Multer in Node.js where I can't seem to select and upload multiple files. In a previous exercise, I had no trouble uploading a single file, but now I'm struggling with enabling multiple uploads. What am I mis ...

The problem arises when the type of a Typescript literal union becomes more specific within React children

Currently, I am in the process of converting our React/Redux project to TypeScript and encountering a challenge with TypeScript literal type union types. The issue that I'm facing is as follows: I have instantiated a Wrapper component with a type pr ...

How can I extract information from an iCal file to display the upcoming event?

Is there a method to extract information from an iCalendar file and display the most recent event using JavaScript or node.js? Your assistance on this matter would be greatly valued. Many thanks ...