Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Component Request - FTVA TabList & Tab #597

Open
farosFreed opened this issue Aug 21, 2024 · 2 comments
Open

Component Request - FTVA TabList & Tab #597

farosFreed opened this issue Aug 21, 2024 · 2 comments
Assignees

Comments

@farosFreed
Copy link
Contributor

farosFreed commented Aug 21, 2024

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 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.

<template>
 <div class='tab' v-show='isActive'>
   <slot></slot>
 </div>
</template>

<script>
const isActive = ref(false)
</script>

Both components together on a page with content for each tab. (Include a story to show a pattern like this)

<div class='page-layout-wrapper'>
    <tablist>
      <tab title="Tab 1 w Icon" :icon="someIconObjectOrString">Tab 1 content goes here</tab>
      <tab title="Tab 2">Tab 2 content goes here</tab>
      <tab title="Tab 3 w Icon" :icon="someOtherIconObjectOrString"><some-component-tab-3-uses /></tab>
      <tab title="Tab 4"><some-other-tab-4-component/></tab>
    </tablist>
 </div>

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:

  • 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).
Screenshot 2024-08-21 at 2 42 45 PM Screenshot 2024-08-21 at 2 42 37 PM

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

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

  1. If implementing icons as strings, you will need to use defineAsyncComponent like BlockAmenities.vue does to load all possible icons.

  2. 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.

  1. update:tab-selected when the activeTab is changed, include the new active tab index like:

emit('update:tab-selected', _activeTabIndex_)

@farosFreed farosFreed self-assigned this Aug 21, 2024
@farosFreed farosFreed changed the title Component Request - FTVA TabList Component Request - FTVA TabList & Tab Aug 22, 2024
@pghorpade
Copy link
Contributor

@axamei Do we need any css transition or animation for this toggle or tab component?
Is this annotated or captured in design system in Figma?

@pghorpade
Copy link
Contributor

@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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants