Search code examples
vuejs3vue-composition-api

Vue 3 Script Setup reactive computed class toggle on click


I'm recently trying to learn Vue 3 with the script setup syntax.

I am dividing some content into four tabs and wish to apply the 'active' class when one is clicked. The string value itself is updating when a tab is clicked, but I cannot seem to get the computed class property to also apply.

My template:

<div
  @click="onTabClick('first')"
  :class="activeState('first')"
>
  <span>First</span>
</div>
<!-- repeated for second, third, and fourth... -->

My script setup:

<script lang="ts" setup>
import { computed } from "vue";

let selectedTab = "";

const activeState = computed(
  () => (tab: string) => selectedTab === tab ? "active" : "inactive",
);

const onTabClick = (tab: string) => {
  selectedTab = tab;
};
</script>

I am thinking I have to use ref somehow to make it reactive, but I haven't been able to find a solution for this setup. Hopefully someone here might know. Is there a way to do it like this or will I have to declare a ref(false) for each tab?


Solution

  • Passing parameters to computed properties should generally be avoided in favor of just using normal methods. See longer explanation here

    As a method:

    const activeState = (tab: string) => selectedTab === tab ? "active" : "inactive";
    

    Another problem with your code however is the fact that the DOM won't update since no reactive variables are being updated. It's easily fixable by making selectedTab into a ref. As a ref, values are assigned to it's .value property.

    const selectedTab = ref("");
    
    const activeState = (tab: string) => selectedTab.value === tab ? "active" : "inactive";
    
    const onTabClick = (tab: string) => {
      selectedTab.value = tab;
    };
    

    Vue Playground demo