What are some creative ways to design the selected tab?

In my Vue parent component, I have multiple child components.

There are several elements that toggle between components by updating the current data.

The issue is that I am unsure how to indicate which tab is currently active.

I've tried various lifecycle hooks like updated, beforeupdated, mounted, created, and beforecreated, but none of them seem to work.

Currently, the code only applies styling to the initial tab (which is "Home"). I want it to highlight only the active tab without affecting others, but unfortunately, it doesn't work as intended.

Most of the time, it either styles all visited links, doesn't work at all, or only works for the initially active tab.

Here is a snippet of the important code from the parent component:


<template>
  <div id="grid">
    <nav id="navbar">

      <ul id="nav">
        <a href="#" class="Home" @click="current = 'Home'" ><li>{{navbar.Home}}</li></a>        
        <a href="#" class="Reservation" @click="current = 'Reservation'" ><li>{{navbar.Reservation}}</li></a>
        <a href="#" class="About-us" @click="current = 'About-us'" ><li>{{navbar.About}}</li></a>
        <a href="#" class="Contact" @click="current = 'Contact'" ><li>{{navbar.Contact}}</li></a>
      </ul>

      <div class="button"> 
        <a href="#">Sign Up
        </a>
      </div>
      <img src="https://i.pinimg.com/564x/8b/fa/5d/8bfa5d6a52a03e83b995fec69a4d8c2c.jpg" alt="" id="logo">
    </nav>      

    <main id="content"> 
      <keep-alive>
        <transition name="component-fade" mode="out-in">
          <component v-bind:is="current"></component>    
        </transition> 
      </keep-alive>          
    </main>      

    <footer>
      <p>Copyright © All Rights Reserved</p>
    </footer>
  </div>
</template>

<script>
import Home from "./components/Home.vue";
import Aboutus from "./components/About us.vue";
import Contact from "./components/Contact.vue";
import Reservation from "./components/Reservation.vue";
import Signup from "./components/Signup.vue";

export default {
  components: {
    Home: Home,
    "About-us": Aboutus,
    Contact: Contact,
    Reservation: Reservation,
    Signup: Signup
  },
  data() {
    return {
      navbar: {
        Home: "Home",
        Reservation: "Reservation",
        About: "About us",
        Contact: "Contact"
      },
      current: "Home"
    };
  },
  mounted: function() {
    let activeTab = document.querySelector("." + this.current);
    activeTab.className = "active";
  },
  beforeUpdate: function() {
    let previousTab = document.querySelector("." + this.current);
    previousTab.className = "none";
  },
  methods: {}
};    

</script>

Answer №1

While I'm not a Vuejs expert, I found an example on the vuejs.org website that may be relevant to what you're looking for in terms of CSS styles.

You can view the sample here: https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components

I hope this information is helpful

<h2 id="Dynamic-Components"><a href="#Dynamic-Components" class="headerlink" title="Dynamic Components"></a>Dynamic Components</h2><p>There are times when dynamically switching between components, such as in a tabbed interface, can be beneficial:</p>

<div id="dynamic-component-demo" class="demo">
  <button v-for="tab in tabs" v-bind:key="tab" class="dynamic-component-demo-tab-button" v-bind:class="{ 'dynamic-component-demo-tab-button-active': tab === currentTab }" v-on:click="currentTab = tab">
    {{ tab }}
  </button>
  <component v-bind:is="currentTabComponent" class="dynamic-component-demo-tab"></component>
</div>
<script>
Vue.component('tab-home', { template: '<div>Home component</div>' })
Vue.component('tab-posts', { template: '<div>Posts component</div>' })
Vue.component('tab-archive', { template: '<div>Archive component</div>' })
new Vue({
  el: '#dynamic-component-demo',
  data: {
    currentTab: 'Home',
    tabs: ['Home', 'Posts', 'Archive']
  },
  computed: {
    currentTabComponent: function () {
      return 'tab-' + this.currentTab.toLowerCase()
    }
  }
})
</script>
<style>
.dynamic-component-demo-tab-button {
  padding: 6px 10px;
  border-top-left-radius: 3px;
  border-top-right-radius: 3px;
  border: 1px solid #ccc;
  cursor: pointer;
  background: #f0f0f0;
  margin-bottom: -1px;
  margin-right: -1px;
}
.dynamic-component-demo-tab-button:hover {
  background: #e0e0e0;
}
.dynamic-component-demo-tab-button-active {
  background: #e0e0e0;
}
.dynamic-component-demo-tab {
  border: 1px solid #ccc;
  padding: 10px;
}
</style>

Answer №2

Everything is functioning as expected. The issue arises when you manipulate the DOM directly, without Vue being aware of it. Vue operates on its own virtual DOM, so it's important to handle changes appropriately. You can follow this example or explore more about dynamic class binding in the Vue guide:

<ul id="nav">
  <a
    href="#"
    class="['Home', current === 'Home' ? 'active' : '']"
    @click="current = 'Home'"
  >
    <li>{{navbar.Home}}</li>
  </a>        
  <a
    href="#"
    class="['Reservation', current === 'Reservation' ? 'active' : '']"
    @click="current = 'Reservation'"
  >
    <li>{{navbar.Reservation}}</li>
  </a>
  <a
    href="#"
    class="['About-us, current === 'About-us' ? 'active' : '']"
    @click="current = 'About-us'"
  >
    <li>{{navbar.About}}</li>
  </a>
  <a
    href="#"
    class="['Contact', current === 'Home' ? 'active' : '']"
    @click="current = 'Contact'"
  >
    <li>{{navbar.Contact}}</li>
  </a>
</ul>

Consider removing the mounted and beforeUpdate hooks...

Note: It is recommended to use button elements for navigation to enhance semantics and accessibility. It is now considered deprecated/antipattern to use a within li tags.

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

Displaying properties of objects in javascript

Just starting with JavaScript and struggling to solve this problem. I attempted using map and filter but couldn't quite implement the if condition correctly. How can I find the records in the given array that have a gender of 0 and color is red? let s ...

How to position an image on top of each printed page using HTML/CSS (SCSS)

I've created a simple and small webpage that looks like this: Everything is perfect in the browser, with all the styles (margin, padding, etc.) just as I want it. However, my issue lies in the print view of the page. As shown in the image above, th ...

Identifying overflow of text or elements in JavaScript during execution

The website I'm working on has a unique design that requires users to scroll horizontally using the Arrow Keys instead of swiping. To achieve this, I must constantly check for overflow in text or elements each time a new page is loaded, and if necessa ...

"Encountering an error in Vue3 CompositionAPI: 'quizz is not defined' while trying to call a function from the

When attempting to call a function, I am encountering an error that says "Uncaught ReferenceError: quizz is not defined." <script setup> import { defineProps } from "vue"; import { useRouter } from "vue-router"; const router = us ...

Perform the function prior to making any adjustments to the viewmodel attributes

Within my view, I am showcasing employee details with a checkbox labeled Receive Daily Email. When a user interacts with this checkbox, I want to trigger an AJAX function to validate whether the user is allowed to modify this setting: If the result is tru ...

Is there a significant distinction between value and defaultValue in React JS?

React's homepage features the final illustration (A Component Using External Plugins) with a textarea: <textarea id="markdown-content" onChange={this.handleChange} defaultValue={this.state.value} /> While typing, the ...

Issues with Internet Explorer's scaling functionality are preventing it from operating correctly

I've utilized d3 to create a map. Its width is dynamically set based on the parent div's (with the id "map") width, and its height is calculated with a ratio of 5/9 in relation to the width. The viewBox attribute has been defined as "0 0 width he ...

Function Errors, How to Fix Them?

I've recently developed a tool for character creation within a new video game. However, I'm currently facing an issue: When it comes to assigning points in Magic Power or Weapon Power for the Warrior and Wizard characters, there seems to be a p ...

"Upon refreshing the Angular app, the index.html file is not loaded

My angular.js application has a basic setup where the index.html file renders static content like Top/Sidebar. Inside, there is a <div ng-view></div> to display partial html files such as home.html. Upon logging into the application, both the ...

Utilizing ControlValueAccessor in various components

I am currently working on a component that implements the ControlValueAccessor interface, and I am facing some difficulties in understanding how to properly utilize it: // Angular Imports import { Component, OnInit, forwardRef, Output, EventEmitter, OnC ...

Determine whether the browser is being used on an Android or iOS device

Is there a dependable method to alter buttons and text on a mobile site based on whether the user is using an Android or iOS browser? ...

Exchange of Fusion Chart

Attempting to perform a fusion chart swap with asp has proven to be challenging. The alternative approach involves rendering the fusion chart first and then using onmousedown to replace the chart with an image. However, this method is also encountering i ...

Increase the spacing around the content in a textfield

I'm trying to figure out how to prevent text in a textfield from extending all the way to the end of the field. My setup includes a textfield with a background image and a button positioned on the right side of the textfield. I want to ensure that the ...

Is there a method for the parent to detect changes in its output when passing around complex objects to its child?

I am facing a challenge with a complex object that is being passed down from a parent component to its child components. The child components further break down this object and pass parts of it to their own children, creating layers of complexity. At times ...

What is the best way to incorporate various styles into one :style attribute?

Within my vuetify project, I encountered a challenge of adding multiple styles to the same style attribute. Specifically, I have successfully implemented a vuetify breakpoint and now wish to include {backgroundColor:'Color'} within the existing a ...

What is the sequence in which Jest executes its tests?

A fascinating challenge I've taken on involves testing a card game created in JavaScript using Jest. Currently, I have developed two tests: one to verify the creation of a 52-card deck and another to confirm that the player is dealt two cards at the ...

The <select> element is experiencing compatibility issues with the camera controls in ThreeJs

I have been developing a ThreeJs application that includes a dropdown menu for user selections, resulting in changes to the displayed objects. However, I have encountered an issue where using the html select tag with camera controls (such as Trackball or ...

Tips for getting rid of the glowing effect on MUI slider thumbs when they are in focus

import * as React from "react"; import Box from "@mui/material/Box"; import Slider from "@mui/material/Slider"; function valuetext(value) { return `${value}°C`; } export default function RangeSlider() { const [value, se ...

Is there a way to create an HTML popup that automatically opens a link and an image file side by side

Can a popup code be created to automatically open both a link and an image side by side? ...

Is it necessary to execute Commit and Begintransaction in SELECT queries?

I'm an MySQL beginner. Should we use commit or beginTransaction in SELECT statements? Let's say the query looks like this db.query("SELECT * FROM my_table") In this scenario, do we need to use commit or beginTransaction? db.query(&quo ...