Migrating from UITabs to HighRise Tabs
This guide will help you migrate from the ghl-ui Tabs component to the new HighRise Tabs component.
Component Implementation Changes
Import Changes
diff
- import { UITabs, UITab, UITabPane } from '@gohighlevel/ghl-ui'
+ import { HLTabs, HLTabPane, renderTabWithIcon,HLTab } from '@platform-ui/highrise'
Breaking Changes
The following architectural changes have been made:
Component Structure:
- Old: Used three components (
UITabs
,UITab
,UITabPane
) - New: Uses two components (
HLTabs
,HLTab
,HLTabPane
) - Simplified architecture with better integration
- Old: Used three components (
Tab Types:
- Old: Supported 'line', 'card', 'bar', 'segment'
- New: Supports 'line' and 'segment' only
- More focused and consistent styling
Tab Configuration:
- Old: Used separate tab components
- New: Uses structured tab objects with enhanced props
- Better type safety and validation
Props Changes
New Required Props:
id
: Required for accessibility
Renamed Props:
animated
→ Removed (animations are now built-in)
New Props:
maxVisibleTabs
: Control number of visible tabs
Removed Props:
type='card'
andtype='bar'
(use 'line' or 'segment')animated
(now built-in)
Slots Changes
New Slots:
overflow
: Custom overflow menu buttonadd-tab
: Add tab buttonend-actions
: Additional actionscustom-slot
: Custom content area
Changed Slots:
- Icon handling now uses
renderTabWithIcon
helper
- Icon handling now uses
Examples
Basic Tabs
diff
- <UITabs v-model:value="activeTab">
- <UITabPane name="tab1" tab="Tab 1">Content for Tab 1</UITabPane>
- <UITabPane name="tab2" tab="Tab 2">Content for Tab 2</UITabPane>
- <UITabPane name="tab3" tab="Tab 3">Content for Tab 3</UITabPane>
- </UITabs>
+ <HLTabs
+ id="basic-tabs"
+ v-model:value="activeTab"
+ >
+ <HLTabPane name="tab1" tab="Tab 1">Content for Tab 1</HLTabPane>
+ <HLTabPane name="tab2" tab="Tab 2">Content for Tab 2</HLTabPane>
+ <HLTabPane name="tab3" tab="Tab 3">Content for Tab 3</HLTabPane>
+ </HLTabs>
UITab Usage
diff
- <UITabs v-model:value="activeTab">
- <UITab name="tab1" key="tabkey1">Tab 1</UITab>
- <UITab name="tab2" key="tabkey2">Tab 2</UITab>
- <UITab name="tab3" key="tabkey3">Tab 3</UITab>
- </UITabs>
+ <HLTabs
+ id="basic-tabs"
+ v-model:value="activeTab"
+ >
+ <HLTab name="tab1" tab-key="tabkey1">Tab 1</HLTab>
+ <HLTab name="tab2" tab-key="tabkey2">Tab 2</HLTab>
+ <HLTab name="tab3" tab-key="tabkey3">Tab 3</HLTab>
+ </HLTabs>
Tabs with Icons
vue
<template>
<HLTabs id="tabs-with-icons">
<HLTabPane
name="payment"
:tab="
renderTabWithIcon({
iconOnly: false,
tab: 'Payment',
icon: CreditCard01Icon,
tabSize: 'md',
})
"
>
Payment content
</HLTabPane>
<HLTabPane
name="settings"
:tab="
renderTabWithIcon({
iconOnly: false,
tab: 'Settings',
icon: Settings01Icon,
tabSize: 'md',
})
"
>
Settings content
</HLTabPane>
</HLTabs>
</template>
<script setup>
import { HLTabs, HLTabPane, renderTabWithIcon } from '@platform-ui/highrise'
import { CreditCard01Icon, Settings01Icon } from '@gohighlevel/ghl-icons/24/outline'
</script>
Segment Style Tabs
diff
- <UITabs type="segment" v-model:value="activeTab">
- <UITabPane name="tab1" tab="Tab 1">Content for Tab 1</UITabPane>
- <UITabPane name="tab2" tab="Tab 2">Content for Tab 2</UITabPane>
- </UITabs>
+ <HLTabs
+ id="segment-tabs"
+ type="segment"
+ v-model:value="activeTab"
+ >
+ <HLTabPane name="tab1" tab="Tab 1">Content for Tab 1</HLTabPane>
+ <HLTabPane name="tab2" tab="Tab 2">Content for Tab 2</HLTabPane>
+ </HLTabs>
With Navigation Arrows
vue
<template>
<HLTabs id="tabs-with-arrows" type="segment" :value="activeTab" @update:value="updateValue">
<HLTabPane name="tab1" tab="Tab 1">Content for Tab 1</HLTabPane>
<HLTabPane name="tab2" tab="Tab 2">Content for Tab 2</HLTabPane>
<HLTabPane name="tab3" tab="Tab 3">Content for Tab 3</HLTabPane>
<template #prefix>
<ArrowLeftIcon class="w-4 h-4 cursor-pointer" @click="handleClick(true)" />
</template>
<template #suffix>
<ArrowRightIcon class="w-4 h-4 cursor-pointer" @click="handleClick(false)" />
</template>
</HLTabs>
</template>
<script setup>
import { ref } from 'vue'
import { ArrowLeftIcon, ArrowRightIcon } from '@gohighlevel/ghl-icons/24/outline'
const activeTab = ref('tab1')
const tabKeys = ['tab1', 'tab2', 'tab3']
const handleClick = (increment = true) => {
const len = tabKeys.length
const index = tabKeys.indexOf(activeTab.value)
const newIndex = index + (increment ? 1 : -1) < 0 ? len - 1 : (index + (increment ? 1 : -1)) % len
activeTab.value = tabKeys[newIndex]
}
const updateValue = newVal => {
activeTab.value = newVal
}
</script>
With Overflow Menu
vue
<template>
<HLTabs id="tabs-with-overflow" type="segment" :max-visible-tabs="4">
<HLTabPane name="tab1" tab="Tab 1">Content for Tab 1</HLTabPane>
<HLTabPane name="tab2" tab="Tab 2">Content for Tab 2</HLTabPane>
<HLTabPane name="tab3" tab="Tab 3">Content for Tab 3</HLTabPane>
<HLTabPane name="tab4" tab="Tab 4">Content for Tab 4</HLTabPane>
<HLTabPane name="tab5" tab="Tab 5">Content for Tab 5</HLTabPane>
<template #overflow>
<HLButton id="overflow-button" size="3xs" variant="ghost">
<template #icon>
<DotsHorizontalIcon />
</template>
</HLButton>
</template>
<template #end-actions>
<HLButton id="add-tab" size="3xs" variant="ghost">
<template #icon>
<PlusIcon />
</template>
</HLButton>
</template>
</HLTabs>
</template>
Type Definitions
typescript
type TabPlacement = 'top' | 'right' | 'bottom' | 'left'
type TabType = 'line' | 'segment'
type TabSize = 'sm' | 'md' | 'lg'
type TabJustifyContent = 'start' | 'end' | 'space-around' | 'space-between' | 'space-evenly' | 'center'
interface TabIconConfig {
iconOnly: boolean
tab: string
icon: Component
tabSize: TabSize
}
interface HLTabsProps {
id: string
placement?: TabPlacement
type?: TabType
value?: string
defaultValue?: string
justifyContent?: TabJustifyContent
size?: TabSize
maxVisibleTabs?: number
}
Best Practices
- Always provide unique
id
props for accessibility - Use appropriate tab types for different contexts
- Consider overflow behavior for many tabs
- Implement proper navigation patterns
- Use icons consistently across tabs
- Keep tab labels concise
- Group related content logically
- Consider mobile responsiveness
- Implement proper loading states
- Follow accessibility guidelines
Additional Notes
- The component provides built-in responsive design
- Enhanced overflow handling
- Support for custom icons
- Improved accessibility features
- Consistent styling with HighRise
- Support for RTL layouts
- Better mobile support
- Flexible layout options
- Integration with other HighRise components
- Built-in support for dynamic tabs
Common Migration Patterns
1. Basic Tab Replacement
The most straightforward migration involves replacing the component names and adding the required id
prop:
diff
- import { UITabs, UITab, UITabPane } from '@gohighlevel/ghl-ui'
+ import { HLTabs, HLTabPane } from '@platform-ui/highrise'
- <UITabs v-model="selectedTab">
- <UITabPane name="profile" tab="Profile">
- Profile content
- </UITabPane>
- </UITabs>
+ <HLTabs
+ id="profile-tabs"
+ v-model:value="selectedTab"
+ size="lg"
+ >
+ <HLTabPane
+ name="profile"
+ tab="Profile"
+ >
+ Profile content
+ </HLTabPane>
+ </HLTabs>
2. Replacing Card and Bar Types
For components using removed tab types:
diff
- <UITabs type="card">
- <UITab name="settings">Settings</UITab>
- <UITabPane>Settings content</UITabPane>
- </UITabs>
+ <!-- Replace card with line type -->
+ <HLTabs
+ id="settings-tabs"
+ type="segment"
+ size="lg"
+ >
+ <HLTab name="settings">Settings</HLTab>
+ <HLTabPane>Settings content</HLTabPane>
+ </HLTabs>
- <!-- Bar type replacement -->
- <UITabs type="bar">
- <UITab name="analytics">Analytics</UITab>
- <UITabPane>Analytics content</UITabPane>
- </UITabs>
+ <!-- Replace bar with segment type -->
+ <HLTabs
+ id="analytics-tabs"
+ type="line"
+ size="lg"
+ >
+ <HLTab name="analytics">Analytics</HLTab>
+ <HLTabPane>Analytics content</HLTabPane>
+ </HLTabs>
3. Migrating Icon Tabs
Old implementation with direct icon usage:
vue
<!-- Old implementation -->
<UITabs>
<UITab name="dashboard">
<template #icon>
<DashboardIcon class="w-4 h-4" />
</template>
Dashboard
</UITab>
<UITabPane>Dashboard content</UITabPane>
</UITabs>
<!-- New implementation using renderTabWithIcon -->
<template>
<HLTabs id="dashboard-tabs">
<HLTabPane
name="dashboard"
:tab="
renderTabWithIcon({
iconOnly: false,
tab: 'Dashboard',
icon: DashboardIcon,
tabSize: 'md',
})
"
>
Dashboard content
</HLTabPane>
</HLTabs>
</template>
<script setup>
import { HLTabs, HLTabPane, renderTabWithIcon } from '@platform-ui/highrise'
import { DashboardIcon } from '@gohighlevel/ghl-icons/24/outline'
</script>
4. Replacing Tab Events
Old implementation with events:
vue
<!-- Old implementation -->
<UITabs v-model="activeTab" @tab-click="handleTabClick" @tab-change="handleTabChange">
<UITab name="events">Events</UITab>
<UITabPane>Events content</UITabPane>
</UITabs>
<!-- New implementation -->
<template>
<HLTabs id="events-tabs" :value="activeTab" @update:value="handleTabChange" @click="handleTabClick">
<HLTabPane name="events" tab="Events"> Events content </HLTabPane>
</HLTabs>
</template>
<script setup>
import { ref } from 'vue'
import { HLTabs, HLTabPane } from '@platform-ui/highrise'
const activeTab = ref('events')
const handleTabChange = newValue => {
activeTab.value = newValue
// Additional change handling
}
const handleTabClick = event => {
// Click handling
}
</script>
Props Changes
size Mapping
ghl-ui size | HighRise size |
---|---|
small | md |
medium | lg |
large | lg |