skip to Main Content

I’ve set up a sandbox to show what I’m trying to do, but essentially I want to get the content of the tabs to scroll when needed and otherwise for the tab to fill to the bottom, I’m sure the trick will be to use flex columns, but nothing i’m trying seems to work

https://codesandbox.io/p/sandbox/primevue-demo-forked-ww2zq7?file=/src/App.vue:111,25

2

Answers


  1. Solution

    You only need to override the CSS formatting of a few PrimeVue classes, I’ll show you an example using a CDN.

    Header to left side

    To add a bit of dynamism, I created a .vertical-header class. If you associate this with the TabPanel, the header will automatically become vertical on the left side.

    /* Header container | Content container */
    .p-tabview.p-component.vertical-header {
      display: flex;
      flex-direction: row;
    }
    
    /* Header 1, 2, 3 */
    .p-tabview.p-component.vertical-header > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    
    /* Header right border when not selected */
    .p-tabview.p-component.vertical-header > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li:not(.p-highlight) > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-right-width: 2px;
      border-right-color: #dee2e6;
      border-radius: 0;
    }
    
    /* Header right border when selected */
    .p-tabview.p-component.vertical-header > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li.p-highlight > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-right-width: 2px;
      border-radius: 0;
    }
    
    Header to right side

    Using the same technique, it could also be dynamically positioned on the right side (using flex-row-reverse and replacing the right border with the left border).

    /* Content container | Header container */
    .p-tabview.p-component.vertical-header {
      display: flex;
      flex-direction: row-reverse;
    }
    
    /* Header 1, 2, 3 */
    .p-tabview.p-component.vertical-header > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    
    /* Header left border when not selected */
    .p-tabview.p-component.vertical-header > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li:not(.p-highlight) > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-left-width: 2px;
      border-left-color: #dee2e6;
      border-radius: 0;
    }
    
    /* Header left border when selected */
    .p-tabview.p-component.vertical-header > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li.p-highlight > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-left-width: 2px;
      border-radius: 0;
    }
    

    Example

    // CDN Vue Import
    const { createApp, ref } = Vue
    
    const app = createApp({
      setup() {
        const isVertical = ref(true)
        const verticalSide = ref('left') // 'left' or 'right'
        
        const toggleOrientation = () => isVertical.value = !isVertical.value
        const toggleVerticalSide = () => verticalSide.value = verticalSide.value === 'left' ? 'right' : 'left'
        
        return { isVertical, verticalSide, toggleOrientation, toggleVerticalSide }
      },
      components: {
        "TabView": primevue.tabview,
        "TabPanel": primevue.tabpanel,
      },
      template: `
        <div style="margin-bottom: 20px;">
          <button @click="toggleOrientation">Change Vertical/Horizontal</button>
          <button @click="toggleVerticalSide">Change Left/Right</button>
        </div>
        
        <TabView :class="{
          'vertical-header-left': isVertical && verticalSide === 'left',
          'vertical-header-right': isVertical && verticalSide === 'right',
        }">
          <TabPanel header="Header 1">
            <p>Lorem ipsum dolor sit amet, consectetur.</p>
          </TabPanel>
          <TabPanel header="Header 2">
            <p>Sed ut perspiciatis unde omnis iste natus error.</p>
          </TabPanel>
          <TabPanel header="Header 3">
            <p>At vero eos et accusamus et iusto odio dignissimos ducimus.</p>
          </TabPanel>
        </TabView>
      `
    }).mount('#app')
    /**
     ** VERTICAL HEADER TO LEFT
     *
     * .vertical-header-left
     */
    
    /* Header container | Content container */
    .p-tabview.p-component.vertical-header-left {
      display: flex;
      flex-direction: row;
    }
    
    /* Header 1, 2, 3 */
    .p-tabview.p-component.vertical-header-left > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    
    /* Header right border when not selected */
    .p-tabview.p-component.vertical-header-left > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li:not(.p-highlight) > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-right-width: 2px;
      border-right-color: #dee2e6;
      border-radius: 0;
    }
    
    /* Header right border when selected */
    .p-tabview.p-component.vertical-header-left > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li.p-highlight > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-right-width: 2px;
      border-radius: 0;
    }
    
    /**
     ** VERTICAL HEADER TO RIGHT
     *
     * .vertical-header-right
     */
     
     /* Content container | Header container */
    .p-tabview.p-component.vertical-header-right {
      display: flex;
      flex-direction: row-reverse;
    }
    
    /* Header 1, 2, 3 */
    .p-tabview.p-component.vertical-header-right > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav {
      display: flex;
      flex-direction: column;
      gap: 4px;
    }
    
    /* Header left border when not selected */
    .p-tabview.p-component.vertical-header-right > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li:not(.p-highlight) > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-left-width: 2px;
      border-left-color: #dee2e6;
      border-radius: 0;
    }
    
    /* Header left border when selected */
    .p-tabview.p-component.vertical-header-right > .p-tabview-nav-container > .p-tabview-nav-content > .p-tabview-nav > li.p-highlight > .p-tabview-nav-link {
      border-bottom-width: 0px;
      border-left-width: 2px;
      border-radius: 0;
    }
    <link rel="stylesheet" href="https://unpkg.com/primevue/resources/themes/lara-light-blue/theme.css" />
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/resources/primevue.min.css" rel="stylesheet">
    
    <script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/core/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/primevue/3.32.2/tabview/tabview.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/primevue/3.32.2/tabpanel/tabpanel.min.js"></script>
    
    <div id="app"></div>
    Login or Signup to reply.
  2. The TabView automatically handles the content height in PrimeVue, so you need to set the entire TabView container to a fixed size. After this, it’s advisable to align the nav-container fixed to the top using CSS.

    /* Set TabView height */
    .p-tabview.p-component {
      height: 300px;
      overflow: auto;
    }
    
    /* Set Header's position to top */
    .p-tabview.p-component > .p-tabview-nav-container {
      position: sticky;
      top: 0;
    }
    
    // CDN Vue Import
    const { createApp, ref, onMounted, onUnmounted } = Vue
    
    const app = createApp({
      setup() {
        const tabViewHeight = ref(0) // Store current height
        const updateHeight = () => {
          tabViewHeight.value = window.innerHeight // Need to save your own diagram instead
          // on your code need to use:
          /*
          // We subtract the total height occupied by the content from the window's height, and then add the currently occupied space by the tabview (since that doesn't need to be subtracted, but it's included in the pageLayout)
          tabViewHeight.value = window.innerHeight -
            document.querySelector('.pageLayout').clientHeight +
            document.querySelector('.body').clientHeight
          */
        }
    
        onMounted(() => {
          updateHeight() // Set first value
          window.addEventListener('resize', updateHeight) // If the window were to be changed
        })
    
        onUnmounted(() => {
          window.removeEventListener('resize', updateHeight)
        })
    
        return { tabViewHeight }
      },
      components: {
        "TabView": primevue.tabview,
        "TabPanel": primevue.tabpanel,
      },
      template: `
        <TabView :style="{ height: tabViewHeight + 'px' }">
          <TabPanel header="Header 1">
            <p v-for="i in 200" :key="i">Lorem ipsum dolor sit amet, consectetur.</p>
          </TabPanel>
          <TabPanel header="Header 2">
            <p>Sed ut perspiciatis unde omnis iste natus error.</p>
          </TabPanel>
          <TabPanel header="Header 3">
            <p>At vero eos et accusamus et iusto odio dignissimos ducimus.</p>
          </TabPanel>
        </TabView>
      `
    }).mount('#app')
    /* Set TabView height */
    .p-tabview.p-component {
      overflow: auto;
    }
    
    /* Set Header's position to top */
    .p-tabview.p-component > .p-tabview-nav-container {
      position: sticky;
      top: 0;
    }
    <link rel="stylesheet" href="https://unpkg.com/primevue/resources/themes/lara-light-blue/theme.css" />
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/resources/primevue.min.css" rel="stylesheet">
    
    <script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/core/core.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/primevue/3.32.2/tabview/tabview.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/primevue/3.32.2/tabpanel/tabpanel.min.js"></script>
    
    <div id="app"></div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search