<p-tabs class="-vertical" :titles="['First Tab', 'Second Tab', 'Third Tab']">
<template #tabpanel-1>
<h5>Amet dignissimos laboriosam aspernatur!</h5>
<p>Elit vitae itaque repudiandae necessitatibus eligendi. Fugit quis voluptatibus explicabo fugiat consequuntur Atque distinctio quas pariatur beatae accusantium. Quo voluptatibus distinctio hic in quia. Nostrum pariatur neque libero error maxime?</p>
</template>
<template #tabpanel-2>
<h5>Amet libero veritatis illum.</h5>
<p>Ipsum dolorum illo laudantium modi corporis magni, amet Laborum laboriosam necessitatibus sed soluta eligendi. Odio in assumenda consequuntur temporibus dolor. Incidunt quia veniam illum inventore ipsum accusantium. Aperiam dolores itaque</p>
</template>
<template #tabpanel-3>
<h5>Dolor cupiditate quibusdam eveniet</h5>
<p>Consectetur odio tenetur voluptates nemo accusantium architecto, placeat. Minus incidunt a facere delectus modi? Ipsa ratione iste ab consectetur eveniet. Sapiente quisquam quaerat quod distinctio rerum explicabo Mollitia quam sequi?</p>
</template>
</p-tabs>
@use "@imarc/pronto/resources/styles/imported" as *;
/**
* this is a component specific property for animating.
*/
@property --tab__button-box-shadow {
syntax: "<length>";
inherits: false;
initial-value: 0;
}
/**
* @uses PTabs
*/
.tabs {
$b: &;
&__tablist {
display: flex;
justify-content: space-between;
gap: .5rem;
overflow: clip;
@include at(sm) {
border: solid var(--color-gray-300);
border-width: 0 0 2px;
gap: 2rem;
justify-content: start;
}
@include at(md) {
gap: 3rem;
}
}
&__button {
background: #0000;
border: 0;
color: inherit;
cursor: pointer;
display: none;
font: inherit;
white-space: nowrap;
outline-offset: 2px;
transition:
color var(--root-duration-fast) var(--root-ease-out),
--tab__button-box-shadow var(--root-duration-fast) var(--root-ease-out);
@include at(sm) {
display: block;
box-shadow: 0 var(--tab__button-box-shadow) var(--accent-color) inset;
padding: 0 0 8px;
&:hover {
--tab__button-box-shadow: -2px;
box-shadow: 0 var(--tab__button-box-shadow) var(--accent-color-400) inset;
color: var(--color-gray-900);
}
}
&.-selected {
display: block;
--tab__button-box-shadow: -8px;
color: var(--color-gray-900);
}
}
&__panel {
padding: 1rem 0;
}
&__prev,
&__next {
flex-shrink: 0;
}
@include at(sm) {
#{$b}__prev,
#{$b}__next {
background: red;
display: none;
}
}
&.-vertical {
@include at(sm) {
display: grid;
grid: auto / auto 1fr;
#{$b}__tablist {
flex-direction: column;
border-width: 0 2px 0 0;
gap: 2rem;
}
#{$b}__button {
padding: 0 1rem 0 0;
text-align: right;
box-shadow: var(--tab__button-box-shadow) 0 var(--accent-color) inset;
}
#{$b}__panel {
padding: 0 1rem;
}
}
}
&.-solid {
@include at(sm) {
#{$b}__tablist {
border: 0;
gap: .5rem;
}
#{$b}__button {
white-space: nowrap;
background: var(--color-gray-100);
border-radius: .5rem;
box-shadow: 0px 1px 1px 0px var(--color-gray-200);
padding: .5rem 1rem;
margin-bottom: .5rem;
&:hover {
background: #fff;
box-shadow: var(--root-box-shadow-med);
border-radius: 8px;
}
&.-selected {
background: #fff;
border-radius: 8px 8px 0 0;
box-shadow: 0 .5rem 0 #fff;
}
}
#{$b}__panel {
background: #fff;
padding: 1rem;
}
}
}
}
<script setup>
import { computed, ref, useTemplateRef, isRef, isReactive, watchEffect } from 'vue'
import focusWithArrows from '/resources/js/composables/focusWithArrows'
const props = defineProps({
titles: { type: Array, required: true },
})
const tablist = useTemplateRef('tablist')
const visibleTab = ref(0)
const focusedElement = focusWithArrows(tablist)
watchEffect(() => {
if (focusedElement.value) {
visibleTab.value = tablist.value.indexOf(focusedElement.value)
}
})
const tabs = computed(() => props.titles.map((title, i) => ({
title,
selected: i === visibleTab.value,
tabindex: i === visibleTab.value ? 0 : -1,
buttonId: `tab-${i + 1}`,
panelId: `tabpanel-${i + 1}`,
})))
const prev = () => {
const selected = tabs.value.findIndex(e => e.selected)
if (selected) {
focusedElement.value = tablist.value[selected - 1]
}
}
const next = () => {
const selected = tabs.value.findIndex(e => e.selected)
if (selected < tabs.value.length) {
focusedElement.value = tablist.value[selected + 1]
}
}
</script>
<template>
<div class="tabs">
<div class="tabs__tablist" role="tablist" aria-label="Sample Tabs">
<button class="tabs__prev button -circle" @click="prev">
<span class="srOnly">previous</span>
<svg class="button__icon"><use href="/main-icons-sprite.svg#chevron-left" /></svg>
</button>
<button
class="tabs__button"
:class="{ '-selected': tab.selected }"
v-for="tab in tabs"
role="tab"
:aria-selected="tab.selected"
:aria-controls="tab.panelId"
:id="tab.buttonId"
ref="tablist"
:tabindex="tab.tabindex"
v-text="tab.title"
></button>
<button class="tabs__next button -circle" @click="next">
<span class="srOnly">next</span>
<svg class="button__icon"><use href="/main-icons-sprite.svg#chevron-right" /></svg>
</button>
</div>
<div
class="tabs__panel"
v-for="tab in tabs"
role="tabpanel"
:tabindex="tab.tabindex"
:id="tab.panelId"
:aria-labelledby="tab.buttonId"
:hidden="!tab.selected"
>
<slot :name="tab.panelId" />
</div>
</div>
</template>