Search code examples
cssvue.jsclassstylesprimevue

Condtional overwrite Primevue Class p-accordion-header


I am trying to find a solution for overwriting the primevue component class p-accordion-header to have different styles depending on the status of the rendered component that I can get with the variantNumber.

This is what my code looks like:

  <Accordion :multiple="true">
    <AccordionTab
      v-for="variantNumber in variants?.keys()"
      :key="'V' + variantNumber"
    >
    </AccordionTab>
  </Accordion>

where variants is a simple list.

Imagine I have a function that returns the current class name called getCurrentVariantClass(variantNumber).

  1. I can't add a class to the AccordionTab because it would be a non-props attribute.
  2. I tried to wrap a div or a simple html tag around the AccordionTab and add a class there but the component won't render.

How am I supposed to overwrite the styles of p-accordion-header conditionally?


Solution

  • To be able to customize AccordionTab to receive a variant prop, we could create a new component that uses the extends option, and add the prop there:

    <!-- MyAccordionTab.vue -->
    <script>
    import { defineComponent } from 'vue'
    import AccordionTab from 'primevue/accordiontab'
    
    export default defineComponent({
      name: 'AccordionTab', // must be named "AccordionTab" for Accordion to detect it
      extends: AccordionTab,
      props: {
        variant: Number, 👈
      },
      render: AccordionTab.render,
    })
    </script>
    

    Using the same technique above, extend the Accordion component to override its getTabHeadherClass() method that conditionally adds a class based on the given tab's variant prop:

    <!-- MyAccordion.vue -->
    <script>
    import { defineComponent } from 'vue'
    import Accordion from 'primevue/accordion'
    
    export default defineComponent({
      extends: Accordion,
      methods: {
        getTabHeaderClass(tab, i) {
          const headerClasses = Accordion.methods.getTabHeaderClass.call(this, tab, i)
          const variantClass = this.getCurrentVariantClass(tab.props.variant)
          return headerClasses.concat(variantClass)
        },
        getCurrentVariantClass(variantNumber) {
          switch (variantNumber) {
            case 1:
              return 'p-accordion-header-variant-a'
            case 2:
              return 'p-accordion-header-variant-b'
            case 3:
              return 'p-accordion-header-variant-c'
          }
        },
      },
      render: Accordion.render,
    })
    </script>
    
    <style scoped>
    .p-accordion-header-variant-a .p-accordion-header-link {
      border: solid 1px red;
    }
    .p-accordion-header-variant-b .p-accordion-header-link {
      border: solid 1px green;
    }
    .p-accordion-header-variant-c .p-accordion-header-link {
      border: solid 1px blue;
    }
    </style>
    

    Finally, use those new components in your app:

    <!-- App.vue -->
    <script setup>
    import Accordion from '@/components/MyAccordion.vue'
    import AccordionTab from '@/components/MyAccordionTab.vue'
    
    const tabs = [/*...*/]
    </script>
    
    <template>
      <Accordion multiple>
        <AccordionTab v-for="tab in tabs" :key="tab.title" :variant="tab.variant" :header="tab.title">
          <p>{{ tab.content }}</p>
        </AccordionTab>
      </Accordion>
    </template>
    

    demo