This is Tab 1
This is Tab 2
This is Tab 3
---
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
// define the tab's titles
const tabs = [{ title: "Tab 1" }, { title: "Tab 2" }, { title: "Tab 3" }]
---
<Tabs id="tabs-sample-1" tabs={tabs} client:visible>
<!-- tab1 -->
<div class="p-4" slot="tab-content-1">
<span>This is Tab 1</span>
</div>
<!-- tab2 -->
<div class="p-4" slot="tab-content-2">
<span>This is Tab 2</span>
</div>
<!-- tab3 -->
<div class="p-4" slot="tab-content-3">
<span>This is Tab 3</span>
</div>
</Tabs>
<style is:global>
/* This is just to force full width on Astro live preview */
div > * :has(.astro-tabs) {
width: 100%;
}
</style>- →
<Tabs/>: The mainTabscomponent - → props.id : STRING value required for the component
- → props.tabs : ARRAY of tab collection to build the tabs header/nav
- → props.tabs.title : Set the tab header/nav title
- → default tab : Utilise v-model for setting default tab
- → props.headerClass : Additional Classes for astro-tabs__header
- → props.dropdownClass : Additional Classes for astro-tabs__dropdown
- → Icons : Utilise named Slot with this pattern —
tab-icon-{tab position}e.g.<IconName slot="tab-icon-1">to set the tab icon for the first tab. - → Contents : Utilise named Slot with this pattern —
tab-content-{tab position}e.g.<div class="p-4" slot="tab-content-1">to set the tab content for the first tab.
States
Mobile
Select screen size:
You can also drag the container horizontally to resize!
This is Tab 1
This is Tab 2
This is Tab 3
---
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
// define the tab's titles
const tabs = [{ title: "Tab 1" }, { title: "Tab 2" }, { title: "Tab 3" }]
let screenSizes = [
{ xs: "320px" },
{ sm: "384px" },
{ md: "448px" },
{ lg: "512px" },
{ xl: "576px" },
{ "2xl": "672px" },
{ "3xl": "768px" },
]
---
<astro-responsive-container>
<p class="mb-4">Select screen size:</p>
<div class="screen-options flex flex-wrap gap-4 mb-4">
{
screenSizes.map((screen) =>
Object.entries(screen).map(([key, value]) => (
<span key={key}>
<input
type="radio"
id={key}
name="responsive-screens"
value={value}
/>
<label for={key} class="cursor-pointer">
<strong>{key}</strong> ({value})
</label>
</span>
)),
)
}
</div>
<p class="mb-4">You can also drag the container horizontally to resize!</p>
<div
class:list={[
"responsive-container",
"border-[1px] border-dashed border-ui-warning-500",
"overflow-hidden",
"p-4",
"resize-x",
"max-w-full",
]}
>
<Tabs
id="tabs-sample-2"
tabs={tabs}
dropdownClass="flex justify-center"
client:visible
>
<!-- tab1 -->
<div class="p-4" slot="tab-content-1">
<span>This is Tab 1</span>
</div>
<!-- tab2 -->
<div class="p-4" slot="tab-content-2">
<span>This is Tab 2</span>
</div>
<!-- tab3 -->
<div class="p-4" slot="tab-content-3">
<span>This is Tab 3</span>
</div>
</Tabs>
</div><!-- /.responsive-container -->
</astro-responsive-container>
<script>
class AstroResponsiveContainer extends HTMLElement {
constructor() {
super()
this.radios = this.querySelectorAll('input[name="responsive-screens"]')
this.container = this.querySelector(".responsive-container")
}
connectedCallback() {
if (this.radios) {
this.radios.forEach((radio) => {
radio.addEventListener("change", (event) => {
if (event.target.checked) {
this.setContainerWidth(event.target)
}
})
})
//set default
this.radios[0].checked = true
this.setContainerWidth(this.radios[0])
}
}
setContainerWidth(radio) {
this.container.style.width = radio.value
}
}
customElements.define("astro-responsive-container", AstroResponsiveContainer)
</script>
<style>
.responsive-container {
background-image: url("data:image/svg+xml,%0A%3Csvg width='544' height='802' viewBox='0 0 544 802' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M2.03 7.66C.57 10.18.46 11.7 1.47 14.63c1.27 3.68 2.19 4.21 27.49 16.87 203.58 101.34 251.9 294.64 263.6 336.3 8.94 32.13 22.85 88.8 22.2 90.29-.22.28-23.28 9.8-51.31 21.15l-50.93 20.71-1.58 3.72c-.96 2.13-1.28 4.88-.86 6.11.43 1.23 3.76 5.69 7.5 9.8 3.68 4.23 16.19 18.43 27.7 31.6 235.31 269.05 217.7 249.2 221.15 250.02 3.93.97 7.27-.39 9.16-3.79.9-1.68 9.81-54.14 19.82-116.6 10.01-62.47 25.02-156.47 33.46-208.77 8.4-52.39 15.08-96.57 14.77-98.37-.46-2.59-1.2-3.5-4.41-5.14-4.8-2.26-.26-3.83-58.75 19.8-25.7 10.44-46.97 18.71-47.32 18.62-.29-.22-2.28-6.62-4.28-14.28-5.92-22.4-38.2-118.31-50.04-148.71C362.1 201.18 305.25 40.54 131.38 7.97A417.34 417.34 0 0 0 49.62.9C34.12 1.05 9.1 2.7 5.88 3.8c-1.04.36-2.76 2.11-3.85 3.86z' fill='%23C9D6E2' fill-rule='evenodd'/%3E%3C/svg%3E");
background-position: calc(100% - 0.25em) calc(100% - 0.5em);
background-size: 2em auto;
background-repeat: no-repeat;
}
</style>Default Opened Tab
This is Tab 3
This is Tab 1
This is Tab 2
This is Tab 4
---
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
// define the tab's titles
const tabs = [
{ title: "Tab 1" },
{ title: "Tab 2" },
{ title: "Tab 3" },
{ title: "Tab 4" },
]
let selectedTab = "tab3"
---
<Tabs id="tabs-sample-3" tabs={tabs} selectedTab={selectedTab} client:visible>
<!-- tab1 -->
<div class="p-4" slot="tab-content-1">
<span>This is Tab 1</span>
</div>
<!-- tab2 -->
<div class="p-4" slot="tab-content-2">
<span>This is Tab 2</span>
</div>
<!-- tab3 -->
<div class="p-4" slot="tab-content-3">
<span>This is Tab 3</span>
</div>
<!-- tab4 -->
<div class="p-4" slot="tab-content-4">
<span>This is Tab 4</span>
</div>
</Tabs>With Icons
This is Tab 1
This is Tab 2
This is Tab 3
This is Tab 4
---
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
import { Download, Smile, ShoppingCart, ExternalLink } from "lucide-vue-next"
// define the tab's titles
const tabs = [
{ title: "Tab 1" },
{ title: "Tab 2" },
{ title: "Tab 3" },
{ title: "Tab 4" },
]
---
<Tabs id="tabs-sample-4" client:visible tabs={tabs}>
<!-- tab1 -->
<Download slot="tab-icon-1" />
<div class="p-4" slot="tab-content-1">
<span>This is Tab 1</span>
</div>
<!-- tab2 -->
<Smile slot="tab-icon-2" />
<div class="p-4" slot="tab-content-2">
<span>This is Tab 2</span>
</div>
<!-- tab3 -->
<ShoppingCart slot="tab-icon-3" />
<div class="p-4" slot="tab-content-3">
<span>This is Tab 3</span>
</div>
<!-- tab4 -->
<ExternalLink slot="tab-icon-4" />
<div class="p-4" slot="tab-content-4">
<span>This is Tab 4</span>
</div>
</Tabs>Center Aligned
Boots Boots Boots Boots Boots Boots
Sneakers: 0
Sneakers: 0
Sneakers: 0
Sneakers: 0
Sneakers: 0
Flip-flops Flip-flops Flip-flops Flip-flops
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Jeans: 40
Cap: Out of stock
---
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
import {
Download,
Smile,
ShoppingCart,
Camera,
ExternalLink,
} from "lucide-vue-next"
// define the tab's titles
const tabs = [
{ title: "Boots" },
{ title: "Sneakers" },
{ title: "Flip-flops" },
{ title: "Jeans" },
{ title: "Cap" },
]
---
<Tabs
id="tabs-sample-5"
headerClass="justify-center"
tabs={tabs}
client:visible
>
<!-- tab1 -->
<Download slot="tab-icon-1" />
<div class="p-4" slot="tab-content-1">
<span>Boots </span>
<span>Boots </span>
<span>Boots </span>
<span>Boots </span>
<span>Boots </span>
<span>Boots </span>
</div>
<!-- tab2 -->
<Smile slot="tab-icon-2" />
<div class="p-4" slot="tab-content-2">
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
</div>
<!-- tab3 -->
<Camera slot="tab-icon-3" />
<div class="p-4" slot="tab-content-3">
<span>Flip-flops</span>
<span>Flip-flops</span>
<span>Flip-flops</span>
<span>Flip-flops</span>
</div>
<!-- tab4 -->
<ExternalLink slot="tab-icon-4" />
<div class="p-4" slot="tab-content-4">
{Array.from({ length: 20 }).map(() => <p>Jeans: 40</p>)}
</div>
<!-- tab5 -->
<ShoppingCart slot="tab-icon-5" />
<div class="p-4" slot="tab-content-5">
<span>Cap: Out of stock</span>
</div>
</Tabs>Right Aligned (VUE Rendering)
Sample rendering within VUE template/component
<script setup lang="ts">
import { onMounted, ref } from "vue"
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
import { Download, Smile, ShoppingCart } from "lucide-vue-next"
// VUE live code specific
const props = defineProps({
code: String,
lang: String,
filename: String,
})
const tabs = ref([])
let selectedTab = ref("")
onMounted(() => {
tabs.value = [
{ title: "Flip-flops" },
{ title: "Boots" },
{ title: "Sneakers" },
]
selectedTab.value = "tab2"
})
</script>
<template>
<Tabs
id="tabs-sample-6"
headerClass="justify-end"
:tabs="tabs"
v-model:selectedTab="selectedTab"
>
<!-- tab1 -->
<template v-slot:tab-icon-1><Download /></template>
<template v-slot:tab-content-1>
<p>Flip-flops: 64</p>
<p>Flip-flops: 64</p>
<p>Flip-flops: 64</p>
<p>Flip-flops: 64</p>
</template>
<!-- tab2 -->
<template v-slot:tab-icon-2><Smile /></template>
<template v-slot:tab-content-2>
<p>Boots: 32</p>
<p>Boots: 32</p>
<p>Boots: 32</p>
<p>Boots: 32</p>
</template>
<!-- tab3 -->
<template v-slot:tab-icon-3><ShoppingCart /></template>
<template v-slot:tab-content-3>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
</template>
</Tabs>
</template>Passing V-MODEL (VUE Rendering)
Sample rendering within VUE template/component
Passing v-model to and from external element
<script setup lang="ts">
import { onMounted, ref } from "vue"
import Tabs from "@technologyadvice/components/ui/tabs/Tabs.vue"
import Dropdown from "@technologyadvice/components/ui/dropdown/Dropdown.vue"
import { Download, Smile, ShoppingCart } from "lucide-vue-next"
// VUE live code specific
const props = defineProps({
code: String,
lang: String,
filename: String,
})
interface Option {
value: string
label: string
}
const tabs = ref([])
let selectedTab = ref("")
const dropDownOptions = ref<Option[]>([])
onMounted(() => {
tabs.value = [
{ title: "Flip-flops" },
{ title: "Boots" },
{ title: "Sneakers" },
]
selectedTab.value = "tab3"
dropDownOptions.value = tabs.value.map((tab, index) => {
return {
value: "tab" + (index + 1),
label: tab.title,
}
})
})
</script>
<template>
<p class="mb-4 text-center">
<em>Passing v-model to and from external element</em>
</p>
<Dropdown
id="sort1"
placeholder="--- Select ---"
:default="selectedTab"
:options="dropDownOptions"
v-model="selectedTab"
:class="['astro-tabs__dropdown', 'flex justify-center mb-4']"
/>
<Tabs
id="tabs-sample-7"
headerClass="justify-center"
:tabs="tabs"
v-model:selectedTab="selectedTab"
>
<!-- tab1 -->
<template v-slot:tab-icon-1><Download /></template>
<template v-slot:tab-content-1>
<p>Flip-flops: 64</p>
<p>Flip-flops: 64</p>
<p>Flip-flops: 64</p>
<p>Flip-flops: 64</p>
</template>
<!-- tab2 -->
<template v-slot:tab-icon-2><Smile /></template>
<template v-slot:tab-content-2>
<p>Boots: 32</p>
<p>Boots: 32</p>
<p>Boots: 32</p>
<p>Boots: 32</p>
</template>
<!-- tab3 -->
<template v-slot:tab-icon-3><ShoppingCart /></template>
<template v-slot:tab-content-3>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
<p class="text-red-500">Sneakers: 0</p>
</template>
</Tabs>
</template>