Accessibility: Full
Translations: Not Needed
Migration Guide: Not Needed
Sidebar
A flexible sidebar layout component that supports both inline and overlay modes with customizable positioning and tab integration.
Default
Pass position="left" to position HLTabs on the left
Sample Sidebar-adjacent Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Dragon Ball
Last updated 2m ago
Configure Tab Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Sample Sidebar-adjacent Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Dragon Ball
Last updated 2m ago
Configure Tab Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. SidebarContainer.vue
vue
<template>
<HLSidebarContainer
id="default-sidebar"
sidebarWidth="320px"
ref="sidebarContainerRef"
v-model:overlay-popover-props="overlayPopoverProps"
>
<div class="p-4 h-full">
<h1 class="m-0">Sample Sidebar-adjacent Content</h1>
<span>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived
not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the
1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like
Aldus PageMaker including versions of Lorem Ipsum.
</span>
</div>
<template #tabs>
<div class="h-full flex flex-col justify-between items-center" :class="$props.position === 'left' ? 'pr-2' : 'pl-2'">
<HLTabs id="just-tabs-demo" sidebar size="md" type="line" @update:value="handleTabChange">
<HLTab name="configure-tab" tab-key="configure" tab="Configure" icon-only>
<HLIcon :size="18">
<CreditCard01Icon />
</HLIcon>
</HLTab>
<HLTab name="payment-tab" tab-key="payment" tab="Payment" icon-only>
<HLIcon :size="18">
<Tool02Icon />
</HLIcon>
</HLTab>
<HLTab name="pin-tab" tab-key="pin" tab="Pin" icon-only>
<HLIcon :size="18">
<Pin02Icon />
</HLIcon>
</HLTab>
</HLTabs>
<div>
<HLDivider class="!my-2" />
<HLPopover content-class="p-2">
<template #trigger>
<HLButton id="btn-end-action" variant="ghost">
<template #icon>
<HLIcon :size="18">
<ArchiveIcon />
</HLIcon>
</template>
</HLButton>
</template>
Sample Custom End-Action
</HLPopover>
</div>
</div>
</template>
<template #sidebar-content>
<div class="p-4 flex flex-col gap-4 bg-white h-full justify-between">
<HLHeaderLite
id="header-lite-sidebar"
title="Dragon Ball"
subtitle="Last updated 2m ago"
size="lg"
:closable="true"
@update:close="handleClose"
/>
<div v-if="selectedTab === 'configure-tab'" class="h-full">
<div style="font-weight: 700">Configure Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'payment-tab'" class="h-full">
<div style="font-weight: 700">Payment Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'pin-tab'" class="h-full">
<div style="font-weight: 700">Pin Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<HLSectionFooter id="footer-1" :top-padding="false" :bottom-padding="false" :horizontal-padding="false">
<HLSectionFooterItem justify="start">
<HLButton id="btn-1" size="2xs" variant="text" link>Learn more</HLButton>
</HLSectionFooterItem>
<HLSectionFooterItem justify="end">
<HLButton id="secondary" size="2xs" variant="secondary" @click="handleClose"> Cancel </HLButton>
<HLButton id="primary" size="2xs" variant="primary" color="blue" @click="handleClose"> Save </HLButton>
</HLSectionFooterItem>
</HLSectionFooter>
</div>
</template>
</HLSidebarContainer>
</template>
<script setup lang="ts">
import { ArchiveIcon, CreditCard01Icon, Pin02Icon, Tool02Icon } from '@gohighlevel/ghl-icons/24/outline'
import { reactive, ref } from 'vue'
import {
HLButton,
HLHeaderLite,
HLIcon,
HLPopover,
HLSectionFooter,
HLSectionFooterItem,
HLSidebarContainer,
HLTab,
HLTabs,
type HLTabsSize,
type HLTabsType,
} from '@platform-ui/highrise'
const overlayPopoverProps = reactive({
show: false,
'on-clickoutside': () => {
overlayPopoverProps.show = false
},
})
const sidebarContainerRef = ref(null)
const selectedTab = ref('configure-tab')
const handleTabChange = (tab: string) => {
selectedTab.value = tab
if (props.overlay) {
overlayPopoverProps.show = true
} else {
sidebarContainerRef.value?.inline.openSidebar()
}
}
const handleClose = () => {
if (props.overlay) {
overlayPopoverProps.show = false
} else {
sidebarContainerRef.value?.inline.closeSidebar()
}
}
</script>Segment Type Tabs
Sample Sidebar-adjacent Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Dragon Ball
Last updated 2m ago
Configure Tab Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. SidebarContainer.vue
vue
<template>
<HLSidebarContainer
id="default-sidebar"
sidebarWidth="320px"
ref="sidebarContainerRef"
v-model:overlay-popover-props="overlayPopoverProps"
>
<div class="p-4 h-full">
<h1 class="m-0">Sample Sidebar-adjacent Content</h1>
<span>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived
not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the
1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like
Aldus PageMaker including versions of Lorem Ipsum.
</span>
</div>
<template #tabs>
<div class="h-full flex flex-col justify-between items-center" :class="$props.position === 'left' ? 'pr-2' : 'pl-2'">
<HLTabs id="just-tabs-demo" sidebar size="md" type="segment" @update:value="handleTabChange">
<HLTab name="configure-tab" tab-key="configure" tab="Configure" icon-only>
<HLIcon :size="18">
<CreditCard01Icon />
</HLIcon>
</HLTab>
<HLTab name="payment-tab" tab-key="payment" tab="Payment" icon-only>
<HLIcon :size="18">
<Tool02Icon />
</HLIcon>
</HLTab>
<HLTab name="pin-tab" tab-key="pin" tab="Pin" icon-only>
<HLIcon :size="18">
<Pin02Icon />
</HLIcon>
</HLTab>
</HLTabs>
<div>
<HLDivider class="!my-2" />
<HLPopover content-class="p-2">
<template #trigger>
<HLButton id="btn-end-action" variant="ghost">
<template #icon>
<HLIcon :size="18">
<ArchiveIcon />
</HLIcon>
</template>
</HLButton>
</template>
Sample Custom End-Action
</HLPopover>
</div>
</div>
</template>
<template #sidebar-content>
<div class="p-4 flex flex-col gap-4 bg-white h-full justify-between">
<HLHeaderLite
id="header-lite-sidebar"
title="Dragon Ball"
subtitle="Last updated 2m ago"
size="lg"
:closable="true"
@update:close="handleClose"
/>
<div v-if="selectedTab === 'configure-tab'" class="h-full">
<div style="font-weight: 700">Configure Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'payment-tab'" class="h-full">
<div style="font-weight: 700">Payment Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'pin-tab'" class="h-full">
<div style="font-weight: 700">Pin Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<HLSectionFooter id="footer-1" :top-padding="false" :bottom-padding="false" :horizontal-padding="false">
<HLSectionFooterItem justify="start">
<HLButton id="btn-1" size="2xs" variant="text" link>Learn more</HLButton>
</HLSectionFooterItem>
<HLSectionFooterItem justify="end">
<HLButton id="secondary" size="2xs" variant="secondary" @click="handleClose"> Cancel </HLButton>
<HLButton id="primary" size="2xs" variant="primary" color="blue" @click="handleClose"> Save </HLButton>
</HLSectionFooterItem>
</HLSectionFooter>
</div>
</template>
</HLSidebarContainer>
</template>
<script setup lang="ts">
import { ArchiveIcon, CreditCard01Icon, Pin02Icon, Tool02Icon } from '@gohighlevel/ghl-icons/24/outline'
import { reactive, ref } from 'vue'
import {
HLButton,
HLHeaderLite,
HLIcon,
HLPopover,
HLSectionFooter,
HLSectionFooterItem,
HLSidebarContainer,
HLTab,
HLTabs,
type HLTabsSize,
type HLTabsType,
} from '@platform-ui/highrise'
const overlayPopoverProps = reactive({
show: false,
'on-clickoutside': () => {
overlayPopoverProps.show = false
},
})
const sidebarContainerRef = ref(null)
const selectedTab = ref('configure-tab')
const handleTabChange = (tab: string) => {
selectedTab.value = tab
if (props.overlay) {
overlayPopoverProps.show = true
} else {
sidebarContainerRef.value?.inline.openSidebar()
}
}
const handleClose = () => {
if (props.overlay) {
overlayPopoverProps.show = false
} else {
sidebarContainerRef.value?.inline.closeSidebar()
}
}
</script>Overlay Variant with hover Trigger
Trigger can be customized from between click (default) and hover
Sample Sidebar-adjacent Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.SidebarContainer.vue
vue
<template>
<HLSidebarContainer
ref="sidebarContainerRef"
id="default-sidebar"
sidebarWidth="320px"
overlay
trigger="hover"
:collapsed="false"
v-model:overlay-popover-props="overlayPopoverProps"
>
<div class="p-4 h-full">
<h1 class="m-0">Sample Sidebar-adjacent Content</h1>
<span>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived
not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the
1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like
Aldus PageMaker including versions of Lorem Ipsum.
</span>
</div>
<template #tabs>
<div class="h-full flex flex-col justify-between items-center" :class="$props.position === 'left' ? 'pr-2' : 'pl-2'">
<HLTabs id="just-tabs-demo" sidebar size="md" type="segment" @update:value="handleTabChange">
<HLTab name="configure-tab" tab-key="configure" tab="Configure" icon-only>
<HLIcon :size="18">
<CreditCard01Icon />
</HLIcon>
</HLTab>
<HLTab name="payment-tab" tab-key="payment" tab="Payment" icon-only>
<HLIcon :size="18">
<Tool02Icon />
</HLIcon>
</HLTab>
<HLTab name="pin-tab" tab-key="pin" tab="Pin" icon-only>
<HLIcon :size="18">
<Pin02Icon />
</HLIcon>
</HLTab>
</HLTabs>
<div>
<HLDivider class="!my-2" />
<HLPopover content-class="p-2">
<template #trigger>
<HLButton id="btn-end-action" variant="ghost">
<template #icon>
<HLIcon :size="18">
<ArchiveIcon />
</HLIcon>
</template>
</HLButton>
</template>
Sample Custom End-Action
</HLPopover>
</div>
</div>
</template>
<template #sidebar-content>
<div class="p-4 flex flex-col gap-4 bg-white h-full justify-between">
<HLHeaderLite
id="header-lite-sidebar"
title="Dragon Ball"
subtitle="Last updated 2m ago"
size="lg"
:closable="true"
@update:close="handleClose"
/>
<div v-if="selectedTab === 'configure-tab'" class="h-full">
<div style="font-weight: 700">Configure Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'payment-tab'" class="h-full">
<div style="font-weight: 700">Payment Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'pin-tab'" class="h-full">
<div style="font-weight: 700">Pin Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<HLSectionFooter id="footer-1" :top-padding="false" :bottom-padding="false" :horizontal-padding="false">
<HLSectionFooterItem justify="start">
<HLButton id="btn-1" size="2xs" variant="text" link>Learn more</HLButton>
</HLSectionFooterItem>
<HLSectionFooterItem justify="end">
<HLButton id="secondary" size="2xs" variant="secondary" @click="handleClose"> Cancel </HLButton>
<HLButton id="primary" size="2xs" variant="primary" color="blue" @click="handleClose"> Save </HLButton>
</HLSectionFooterItem>
</HLSectionFooter>
</div>
</template>
</HLSidebarContainer>
</template>
<script setup lang="ts">
import { ArchiveIcon, CreditCard01Icon, Pin02Icon, Tool02Icon } from '@gohighlevel/ghl-icons/24/outline'
import { reactive, ref } from 'vue'
import {
HLButton,
HLHeaderLite,
HLIcon,
HLPopover,
HLSectionFooter,
HLSectionFooterItem,
HLSidebarContainer,
HLTab,
HLTabs,
type HLTabsSize,
type HLTabsType,
} from '@platform-ui/highrise'
const overlayPopoverProps = reactive({
show: false,
'on-clickoutside': () => {
overlayPopoverProps.show = false
},
})
const sidebarContainerRef = ref(null)
const selectedTab = ref('configure-tab')
const handleTabChange = (tab: string) => {
selectedTab.value = tab
if (props.overlay) {
overlayPopoverProps.show = true
} else {
sidebarContainerRef.value?.inline.openSidebar()
}
}
const handleClose = () => {
if (props.overlay) {
overlayPopoverProps.show = false
} else {
sidebarContainerRef.value?.inline.closeSidebar()
}
}
</script>Manual Control for Custom Implementations
Sample Sidebar-adjacent Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.Dragon Ball
Last updated 2m ago
Configure Tab Content
Lorem Ipsum is simply dummy text of the printing and typesetting industry. SidebarContainer.vue
vue
<template>
<HLSidebarContainer
ref="sidebarContainerRef"
id="default-sidebar"
sidebarWidth="320px"
overlay
trigger="hover"
:collapsed="false"
v-model:overlay-popover-props="overlayPopoverProps"
v-model:collapsed="collapsedRef"
>
<div class="p-4 h-full">
<h1 class="m-0">Sample Sidebar-adjacent Content</h1>
<span>
Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text
ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived
not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the
1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like
Aldus PageMaker including versions of Lorem Ipsum.
</span>
</div>
<template #tabs>
<HLTabs
:id="`just-tabs-demo-${$props.id}`"
ref="tabsRef"
v-model:value="selectedTab"
sidebar
:type="$attrs.tabType as HLTabsType"
:size="$attrs.tabSize as HLTabsSize"
trigger="manual"
>
<HLTab name="configure-tab" tab-key="configure" tab="Configure" icon-only @click="handleTabClick('configure-tab')">
<HLIcon :size="18">
<CreditCard01Icon />
</HLIcon>
</HLTab>
<HLTab name="payment-tab" tab-key="payment" tab="Payment" icon-only @click="handleTabClick('payment-tab')">
<HLIcon :size="18">
<Tool02Icon />
</HLIcon>
</HLTab>
<HLTab name="pin-tab" tab-key="pin" tab="Pin" icon-only @click="handleTabClick('pin-tab')">
<HLIcon :size="18">
<Pin02Icon />
</HLIcon>
</HLTab>
</HLTabs>
</template>
<template #sidebar-content>
<div class="p-4 flex flex-col gap-4 bg-white h-full justify-between">
<HLHeaderLite
id="header-lite-sidebar"
title="Dragon Ball"
subtitle="Last updated 2m ago"
size="lg"
:closable="true"
@update:close="handleClose"
/>
<div v-if="selectedTab === 'configure-tab'" class="h-full">
<div style="font-weight: 700">Configure Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'payment-tab'" class="h-full">
<div style="font-weight: 700">Payment Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<div v-else-if="selectedTab === 'pin-tab'" class="h-full">
<div style="font-weight: 700">Pin Tab Content</div>
<span> Lorem Ipsum is simply dummy text of the printing and typesetting industry. </span>
</div>
<HLSectionFooter id="footer-1" :top-padding="false" :bottom-padding="false" :horizontal-padding="false">
<HLSectionFooterItem justify="start">
<HLButton id="btn-1" size="2xs" variant="text" link @click="handleClose">Learn more</HLButton>
</HLSectionFooterItem>
<HLSectionFooterItem justify="end">
<HLButton id="secondary" size="2xs" variant="secondary" @click="handleClose"> Cancel </HLButton>
<HLButton id="primary" size="2xs" variant="primary" color="blue" @click="handleClose"> Save </HLButton>
</HLSectionFooterItem>
</HLSectionFooter>
</div>
</template>
</HLSidebarContainer>
</template>
<script setup lang="ts">
import { CreditCard01Icon, Pin02Icon, Tool02Icon } from '@gohighlevel/ghl-icons/24/outline'
import { reactive, ref } from 'vue'
import {
HLButton,
HLHeaderLite,
HLIcon,
HLSectionFooter,
HLSectionFooterItem,
HLSidebarContainer,
HLTab,
HLTabs,
type HLTabsSize,
type HLTabsType,
} from '@platform-ui/highrise'
const overlayPopoverProps = reactive({
show: false,
'on-clickoutside': () => {
overlayPopoverProps.show = false
},
})
const sidebarContainerRef = ref(null)
const selectedTab = ref('configure-tab')
const collapsedRef = ref(true)
const tabsRef = ref(null)
const handleTabClick = (tab: string) => {
console.log('tabclick')
if (selectedTab.value === tab) collapsedRef.value = !collapsedRef.value
else collapsedRef.value = false
selectedTab.value = tab
tabsRef.value?.syncBarPosition(tab)
}
const handleClose = () => {
if (props.overlay) {
overlayPopoverProps.show = false
} else {
sidebarContainerRef.value?.inline.closeSidebar()
}
}
</script>Props
| Name | Type | Default | Description |
|---|---|---|---|
| id | string | - | The id of the element |
| sidebarWidth | string | number | 280 | Width of the sidebar (pixels or CSS units) |
| className | string | undefined | Additional CSS class names |
| collapsed | boolean | false | Whether the sidebar is collapsed (controlled) |
| overlay | boolean | false | Whether to use overlay mode instead of inline |
| overlayPopoverProps | HLPopoverProps | undefined | Props to pass to the underlying popover (only overlay mode) |
| position | 'left' | 'right' | 'right' | Position of the sidebar |
| trigger | 'click' | 'hover' | 'click' | Trigger type |
Emits
| Name | Parameters | Description |
|---|---|---|
@update:collapsed | (collapsed: boolean) | Emitted when sidebar collapsed state changes |
Slots
| Name | Parameters | Description |
|---|---|---|
| default | () | Main content area |
| tabs | () | Tab navigation area |
| sidebar-content | () | Content displayed inside the sidebar |
Exposed Methods
Inline Mode Methods
| Method | Parameters | Return Type | Description |
|---|---|---|---|
inline.isCollapsed() | () | boolean | Returns the collapsed boolean value |
inline.openSidebar() | () | void | Open the sidebar |
inline.closeSidebar() | () | void | Close the sidebar |
inline.toggleSidebar() | () | void | Toggle sidebar open / closed |
Overlay Mode Methods
| Method | Parameters | Return Type | Description |
|---|---|---|---|
overlay.getPopoverRef() | () | Ref<HLPopover> | Returns the ref to the HLPopover component in overlay mode |