You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This component is used on several FTVA pages to display a tabbed menu that shows content corresponding to each tab.
It consists of a parent component TabList.vue, which renders a list of Tabs and handles positioning the tab menu to the left or the right of content
Something like this:
(this sample uses options API, may want to refactor to composition API)
<template>
<div class='tabs-list'>
<ul class='tabs-header'>
<li v-for='(tab, index) in tabs'
:key='tab.title'
@click='selectTab(index)'
:class='{"tab-selected": (index == selectedIndex)}'>
{{ tab.icon? }} {{ tab.title }}
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
// shown below in props section
},
data () {
return {
selectedIndex: 0, // the index of the selected tab,
tabs: [] // all of the tabs
}
},
created () {
this.tabs = this.$children // will automatically get the tab objects inside tablist
},
mounted () {
this.selectedIndex = initialSelectedTab // in case the page needs to set tab selection
},
methods: {
selectTab (i) {
this.selectedIndex = i
// loop over all the tabs
this.tabs.forEach((tab, index) => {
tab.isActive = (index === i)
})
}
}
}
</script>
and a child component Tab.vue, which provides a slot for tab content and shows the active slot.
Please also see attached screenshots for quick reference.
Variations:
sometimes tabs have an icon, sometimes they don't. Implementation needs to account for an icon slot or icon name.
sometimes tabs are aligned top-left of the content they reveal, sometimes top-right (with other buttons present to the left).
Animations:
Serena described that the active tab highlight should animate from left to right as the tab changes. Please see images in the design file
Slots
Include a slot for each tabs content in the Tab Component.
Include a slot for additional-filters that the parent can use to add additional filter controls for the visible list (see screenshot)
Props
Props for the tabs array have an optional 'icon' field. This field can either A) allow an icon object to be passed, in which case this component does not need to import all possible icons, but the parent component or page using the tablist would need to provide the icon or B) just take a string to represent an icon name, and have the TabsList component import all possible icons and load the correct one.
Tablist:
props: {
// number corresponding to the index item in the tabs array that is initially selected
initialSelectedTab: {
type: Number,
default: 0
},
tabs: {
type: Array as PropType[]<{ title:string, icon?:string }>, // could also be <{ title:string, icon?:Object }>
default: () => []
},
tabAlignment: {
type: String as PropType<'left' | 'right'>,
default: "left"
},
}
Tab
props: {
// the text displayed on the tab
title: {
type: string,
default: 'tab'
},
}
Styles
As this is a new component, please include 2 styles files for each component:
default style files with css rules for basic layout, positioning, using basic colors. These don't have to look perfect, but majority of css that defines the basic structure of the component should be here.
ftva style files that set ftva specific colors, fonts, anything ftva specific
Developer Tips
If implementing icons as strings, you will need to use defineAsyncComponent like BlockAmenities.vue does to load all possible icons.
When implementing tab hide/show functionality, use v-show instead of v-if where possible to take advantage of vue 'keep alive' behavior for quick tab/switching
Events
Just in case we need to use this component to toggle content elsewhere on the page (instead of directly below tabs), TabList can emit an event when the active tab is changed. This will give us the option to react to a tab change at the page level.
update:tab-selected when the activeTab is changed, include the new active tab index like:
emit('update:tab-selected', _activeTabIndex_)
The text was updated successfully, but these errors were encountered:
@farosFreed Yes, The Tablist should emit an event, and the selected tabIndex to the page where it is added, and the event handler on the page will pass the right data to the SectionTeaserList component. We could also replicate this behavior in a sample vue component in the component library and add a storybook file to test the interaction between these components.
Component Description
This component is used on several FTVA pages to display a tabbed menu that shows content corresponding to each tab.
It consists of a parent component
TabList.vue
, which renders a list of Tabs and handles positioning the tab menu to the left or the right of contentSomething like this:
(this sample uses options API, may want to refactor to composition API)
and a child component
Tab.vue
, which provides a slot for tab content and shows the active slot.Both components together on a page with content for each tab. (Include a story to show a pattern like this)
Design
Design File
https://www.figma.com/design/EKazRIMP4B15bD16UDbOwR/UCLA-Library-Design-System?node-id=11358-810&t=06eB6mjVVAW0i11F-0
This file includes full page designs that include this tablist
https://www.figma.com/design/EKazRIMP4B15bD16UDbOwR/UCLA-Library-Design-System?node-id=2347-31817&t=o4K7FZaDlCWjVARz-0
Please also see attached screenshots for quick reference.
Variations:
Animations:
Serena described that the active tab highlight should animate from left to right as the tab changes. Please see images in the design file
Slots
Include a slot for each tabs content in the Tab Component.
Include a slot for additional-filters that the parent can use to add additional filter controls for the visible list (see screenshot)
![Screenshot 2024-08-21 at 3 01 13 PM](https://private-user-images.githubusercontent.com/7073987/360147982-5aaf7552-cce7-49db-8424-9d8bea943347.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MzkxNTAwOTUsIm5iZiI6MTczOTE0OTc5NSwicGF0aCI6Ii83MDczOTg3LzM2MDE0Nzk4Mi01YWFmNzU1Mi1jY2U3LTQ5ZGItODQyNC05ZDhiZWE5NDMzNDcucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI1MDIxMCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNTAyMTBUMDEwOTU1WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTA4MGEzMjBhMzE0YjI2MTUwMmVhMGIxNjk1Mjk4MzgwYTczOTczYjUxYTFlZDdmNTE5NjcwMjBhY2Q1MmViZSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QifQ.WOSGjCCH_LMzbelNGD8vTevPc7176ddiCVncpkvjF8E)
Props
Props for the tabs array have an optional 'icon' field. This field can either A) allow an icon object to be passed, in which case this component does not need to import all possible icons, but the parent component or page using the tablist would need to provide the icon or B) just take a string to represent an icon name, and have the TabsList component import all possible icons and load the correct one.
Tablist:
Tab
Styles
As this is a new component, please include 2 styles files for each component:
default style files with css rules for basic layout, positioning, using basic colors. These don't have to look perfect, but majority of css that defines the basic structure of the component should be here.
ftva style files that set ftva specific colors, fonts, anything ftva specific
Developer Tips
If implementing icons as strings, you will need to use defineAsyncComponent like BlockAmenities.vue does to load all possible icons.
When implementing tab hide/show functionality, use v-show instead of v-if where possible to take advantage of vue 'keep alive' behavior for quick tab/switching
Events
Just in case we need to use this component to toggle content elsewhere on the page (instead of directly below tabs), TabList can emit an event when the active tab is changed. This will give us the option to react to a tab change at the page level.
update:tab-selected
when the activeTab is changed, include the new active tab index like:emit('update:tab-selected', _activeTabIndex_)
The text was updated successfully, but these errors were encountered: