Migrating from UITabs to HighRise Tabs
HighRise HLTabs supports the same core line/segment styles as UITabs while adding overflow handling and richer slot hooks. HLTabPane remains the primary way to declare tabs; HLTab is available when you need header-only tabs.
Component Implementation Changes
Import Changes
diff
- import { UITabs, UITab, UITabPane } from '@gohighlevel/ghl-ui'
+ import { HLTabs, HLTab, HLTabPane, renderTabWithIcon } from '@platform-ui/highrise'Key Differences
- Tab types: only
'line'and'segment'are supported (card/bar are removed). animatedprop is removed; transitions are handled internally.- Size tokens change from
small|medium|largetosm|md|lg|xl|2xl(defaultmd). - Optional overflow handling via
maxVisibleTabswithoverflow/end-actionsslots. idis optional (use when you need anchors or analytics), not required.
Props Mapping
| ghl-ui Prop | HighRise Prop | Notes |
|---|---|---|
value / v-model:value | value / v-model:value | Same binding pattern |
defaultValue | default-value | Same behavior |
type (line | segment | bar | card) | type (line | segment) | Card/bar removed; pick line or segment |
placement (top | right | bottom | left) | placement | Same values |
justifyContent | justify-content | Same values |
size (small | medium | large) | size (sm | md | lg | xl | 2xl) | Choose closest match (default md) |
animated | – | Removed; transitions handled internally |
| – | maxVisibleTabs | Enables overflow handling and overflow slot |
| – | theme, noBorder, offSet | Styling helpers for HighRise tabs |
id (optional) | id (optional) | Use when you need anchors, analytics, or testing hooks |
Slots
- Existing
prefix/suffixslots remain. - New:
overflow(custom overflow trigger) andend-actions(actions on the right). - Icons: prefer
renderTabWithIconto keep spacing consistent.
Examples
Basic Tabs
vue
<template>
<HLTabs 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>
</template>
<script setup>
import { ref } from 'vue'
const activeTab = ref('tab1')
</script>Tabs with Icons
vue
<template>
<HLTabs>
<HLTabPane name="payment" :tab="renderTabWithIcon({ tab: 'Payment', icon: CreditCard01Icon, tabSize: 'md', iconOnly: false })">
Payment content
</HLTabPane>
<HLTabPane name="settings" :tab="renderTabWithIcon({ tab: 'Settings', icon: Settings01Icon, tabSize: 'md', iconOnly: false })">
Settings content
</HLTabPane>
</HLTabs>
</template>
<script setup>
import { CreditCard01Icon, Settings01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { renderTabWithIcon } from '@platform-ui/highrise'
</script>Segment Tabs with Overflow
vue
<template>
<HLTabs type="segment" :max-visible-tabs="3">
<HLTabPane v-for="tab in tabs" :key="tab" :name="tab" :tab="tab"> {{ tab }} content </HLTabPane>
<template #overflow>
<HLButton size="3xs" variant="ghost">
<template #icon><DotsHorizontalIcon /></template>
</HLButton>
</template>
</HLTabs>
</template>
<script setup>
import { HLTabs, HLTabPane, HLButton } from '@platform-ui/highrise'
import { DotsHorizontalIcon } from '@gohighlevel/ghl-icons/24/outline'
const tabs = ['Tab 1', 'Tab 2', 'Tab 3', 'Tab 4']
</script>Best Practices
- Use
type="segment"for pill/segmented controls,type="line"for standard headers. - Provide concise
tablabels; userenderTabWithIconfor iconized tabs. - Enable
maxVisibleTabsand supply anoverflowslot when tab counts can grow. - Keep
justify-contentaligned with surrounding layout (start/center/end). - Only set
idwhen it is referenced externally (analytics, anchor links).
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
renderTabWithIconhelper
- 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
idprops 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 |