Search code examples
vue.jsvuejs3vuetify.jsvuetifyjs3

Custom icons in expandable panel not working as expected in Vuetify 3


Problem statement : Custom down and up arrows icons are not working as expected on expand/collapse the panels manually.

Requirement : As Vuetify provides default arrows icons at the end on expandable-panel-title, I want to add those at the starting before panel title text. And I am able to successfully do that but the issue I am facing in changing the state of these icons on expand/collapse the panel.

enter image description here

This is how my component design for these expandable panels.

enter image description here

In above diagram, each child component (ChildComponentA/ChildComponentB/ChildComponentC) contains single <v-expansion-panel> that's the reason we can not use v-loop on <v-expansion-panels>. We are just passing the dynamic data for each as a prop from parent component.

With default icons, it is working fine. Here is the playground link.

With custom icons, it is not working. Here is the playground link.


Solution

    1. The first problem I see is that the up/down icon of each item inside the default slot of the title is rendered based on the current value of isAllExpanded, but it should be rendered based on current item's expanded value. You can access it inside the title by replacing
    <v-expansion-panel-title>
       ...default slot contents here
    </v-expansion-panel-title>
    

    ...with:

    <v-expansion-panel-title>
      <template v-slot:default="{ expanded }">
         ...default slot contents here, with access to current item's expanded
      </template>
    </v-expansion-panel-title>
    
    1. Another problem is that you're keeping isAllExpanded in state. It should be a computed returning the computed value of whether or not any of the available panels is not contained in this.panels. This way you don't have to worry about setting it correctly. It's always going to be correct.
      See it working here.

    2. Last, but not least, you should keep your code DRY, including the <template />. Rather than writing a separate <v-expansion-panel> for each panel, you should loop through them using a v-for:
      Working example.