Content Switcher
Content Switcher input component for selecting a single option from multiple choices.
Basic Usage
Renders a group of Content Switcher options from a data array, bound to a single selected value.
Note
Content Switcher components must always be wrapped in a HLRadioGroup component. The value passed via v-model:value determines the checked state of the Content Switcher.
<template>
<HLRadioGroup id="radio-basic-group" v-model:value="value" name="radioGroup1">
<HLContentSwitcher
v-for="song in songs"
:id="'radio-basic-' + song.value"
:key="song.value"
:value="song.value"
:label="song.label"
/>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { songs, value } from './options'
</script>import { ref } from 'vue'
export const value = ref('value1')
export const songs = [
{
value: 'value1',
label: "Rock'n'Roll Star",
},
{
value: 'value2',
label: 'Shakermaker',
},
{
value: 'value3',
label: 'Live Forever',
},
{
value: 'value4',
label: 'Up in the Sky',
},
]All Sizes
Displays every available size (lg, md, sm, xs, 2xs, 3xs) via the size prop on HLRadioGroup.
<template>
<HLRadioGroup id="radio-size-lg" v-model:value="sizeLg" name="radioGroupLg" size="lg">
<HLContentSwitcher id="radio-lg-option1" value="option1" label="Large" />
</HLRadioGroup>
<HLRadioGroup id="radio-size-md" v-model:value="sizeMd" name="radioGroupMd" size="md">
<HLContentSwitcher id="radio-md-option2" value="option2" label="Medium" />
</HLRadioGroup>
<HLRadioGroup id="radio-size-sm" v-model:value="sizeSm" name="radioGroupSm" size="sm">
<HLContentSwitcher id="radio-sm-option3" value="option3" label="Small" />
</HLRadioGroup>
<HLRadioGroup id="radio-size-xs" v-model:value="sizeXs" name="radioGroupXs" size="xs">
<HLContentSwitcher id="radio-xs-option4" value="option4" label="Extra Small" />
</HLRadioGroup>
<HLRadioGroup id="radio-size-2xs" v-model:value="size2xs" name="radioGroup2xs" size="2xs">
<HLContentSwitcher id="radio-2xs-option5" value="option5" label="Double Extra Small" />
</HLRadioGroup>
<HLRadioGroup id="radio-size-3xs" v-model:value="size3xs" name="radioGroup3xs" size="3xs">
<HLContentSwitcher id="radio-3xs-option6" value="option6" label="Triple Extra Small" />
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { ref } from 'vue'
// Each size group is independent, with its own value preselected
const sizeLg = ref('option1')
const sizeMd = ref('option2')
const sizeSm = ref('option3')
const sizeXs = ref('option4')
const size2xs = ref('option5')
const size3xs = ref('option6')
</script>Disabled State
Disables an individual option by setting the disabled prop on that HLContentSwitcher.
<template>
<HLRadioGroup id="radio-disabled-group" v-model:value="value" name="radioGroupDisabled">
<HLContentSwitcher
v-for="song in songs"
:id="'radio-disabled-' + song.value"
:key="song.value"
:value="song.value"
:disabled="song.label === 'Live Forever'"
:label="song.label"
/>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { songs, value } from './options'
</script>import { ref } from 'vue'
export const value = ref('value1')
export const songs = [
{
value: 'value1',
label: "Rock'n'Roll Star",
},
{
value: 'value2',
label: 'Shakermaker',
},
{
value: 'value3',
label: 'Live Forever',
},
{
value: 'value4',
label: 'Up in the Sky',
},
]Custom Icon
You can add icons to each Content Switcher using the icon slot.
<template>
<HLRadioGroup id="radio-icon-group" v-model:value="value" name="radioGroupIcon">
<HLContentSwitcher
v-for="song in songs"
:id="'radio-icon-' + song.value"
:key="song.value"
:value="song.value"
:label="song.label"
>
<template #icon>
<ListIcon />
</template>
</HLContentSwitcher>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { ListIcon } from '@gohighlevel/ghl-icons/24/outline'
import { songs, value } from './options'
</script>import { ref } from 'vue'
export const value = ref('value1')
export const songs = [
{
value: 'value1',
label: "Rock'n'Roll Star",
},
{
value: 'value2',
label: 'Shakermaker',
},
{
value: 'value3',
label: 'Live Forever',
},
]Icon Only
Set only-icon (onlyIcon) to render just the icon slot with no label — a common pattern for compact view toggles. Provide an aria-label on each switcher so the control stays accessible (it passes through to the underlying radio button).
<template>
<HLRadioGroup id="radio-icon-only-group" v-model:value="value" name="radioGroupIconOnly" size="xs">
<HLContentSwitcher id="icon-only-grid" value="grid" :only-icon="true" aria-label="Grid view">
<template #icon>
<Grid01Icon />
</template>
</HLContentSwitcher>
<HLContentSwitcher id="icon-only-list" value="list" :only-icon="true" aria-label="List view">
<template #icon>
<ListIcon />
</template>
</HLContentSwitcher>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { Grid01Icon, ListIcon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('grid')
</script>Custom Font Style
You can use the HLText component to style the label of the Content Switcher.
<template>
<HLRadioGroup
id="radio-custom-font-style-group"
v-model:value="value"
name="radioGroupCustomFontStyle"
size="sm"
>
<HLContentSwitcher
v-for="song in songs"
:id="'radio-basic-' + song.value"
:key="song.value"
:value="song.value"
>
<HLText size="2xl" weight="regular">{{ song.label }}</HLText>
</HLContentSwitcher>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup, HLText } from '@platform-ui/highrise'
import { songs, value } from './options'
</script>import { ref } from 'vue'
export const value = ref('value1')
export const songs = [
{
value: 'value1',
label: "Rock'n'Roll Star",
},
{
value: 'value2',
label: 'Shakermaker',
},
{
value: 'value3',
label: 'Live Forever',
},
{
value: 'value4',
label: 'Up in the Sky',
},
]Theme variants
The Content Switcher supports two theme variants through the theme prop on the HLRadioGroup component:
Neutral theme
Uses theme="neutral" on HLRadioGroup for a subdued, low-emphasis selected state.
Primary theme
Uses theme="primary" on HLRadioGroup for a high-emphasis selected state in the primary color.
<template>
<HLRadioGroup id="radio-theme-primary-group" v-model:value="value" name="radioGroupThemePrimary" theme="primary">
<HLContentSwitcher id="theme-primary-1" value="short" label="Short" />
<HLContentSwitcher id="theme-primary-2" value="medium" label="Medium length" />
<HLContentSwitcher id="theme-primary-3" value="long" label="This is a very long option" />
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('short')
</script><template>
<HLRadioGroup id="radio-theme-neutral-group" v-model:value="value" name="radioGroupThemeNeutral" theme="neutral">
<HLContentSwitcher id="theme-neutral-1" value="short" label="Short" />
<HLContentSwitcher id="theme-neutral-2" value="medium" label="Medium length" />
<HLContentSwitcher id="theme-neutral-3" value="long" label="This is a very long option" />
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('short')
</script>Width Variants
The Content Switcher supports three width variants through the width prop on the HLRadioGroup component:
default: Each Content Switcher takes up only the space it needsequal: All Content Switchers in the group have equal width and will occupy 100% of the container's width, wrapping to the next line if the container is too smallfull: Content Switchers evenly distribute the container's width between them, with text truncating if needed
Default Width
Equal Width
Full Width
<template>
<!-- Default Width -->
<HLRadioGroup id="radio-width-default" v-model:value="value" name="radioGroupDefault">
<HLContentSwitcher id="width-default-1" value="short" label="Short" />
<HLContentSwitcher id="width-default-2" value="medium" label="Medium length" />
<HLContentSwitcher id="width-default-3" value="long" label="This is a long option" />
</HLRadioGroup>
<!-- Equal Width -->
<HLRadioGroup id="radio-width-equal" v-model:value="value" name="radioGroupEqual" width="equal">
<HLContentSwitcher id="width-equal-1" value="short" label="Short" />
<HLContentSwitcher id="width-equal-2" value="medium" label="Medium length" />
<HLContentSwitcher id="width-equal-3" value="long" label="This is a very long option" />
</HLRadioGroup>
<!-- Full Width -->
<HLRadioGroup id="radio-width-full" v-model:value="value" name="radioGroupFull" width="full">
<HLContentSwitcher id="width-full-1" value="short" label="Short" />
<HLContentSwitcher id="width-full-2" value="medium" label="Medium length" />
<HLContentSwitcher id="width-full-3" value="long" label="This is a very long option" />
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLRadioGroup, HLContentSwitcher } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('short')
</script>Event Handling
Listen for selection changes on the HLRadioGroup with @update:value — it fires with the newly selected switcher's value (this is the same thing v-model:value binds to). Individual HLContentSwitchers also emit @change (the native change Event) when picked, if you need to react to a specific option.
Current view: list
<template>
<HLRadioGroup id="events-group" v-model:value="view" name="eventsGroup" @update:value="handleViewUpdate">
<HLContentSwitcher id="events-list" value="list" label="List" @change="handleSwitcherChange" />
<HLContentSwitcher id="events-grid" value="grid" label="Grid" @change="handleSwitcherChange" />
<HLContentSwitcher id="events-board" value="board" label="Board" @change="handleSwitcherChange" />
</HLRadioGroup>
<p>Current view: {{ view }}</p>
</template>
<script setup lang="ts">
import { HLRadioGroup, HLContentSwitcher } from '@platform-ui/highrise'
import { ref } from 'vue'
const view = ref('list')
// Fires with the selected switcher's `value` — the source of truth for selection.
const handleViewUpdate = (val: string | number | boolean) => {
console.log('selected view:', val)
}
// Native change Event from the individual switcher that was picked.
const handleSwitcherChange = (event: Event) => {
console.log('switcher changed', event)
}
</script>Accessibility
- Present the switcher as
role="radiogroup"orrole="tablist"and describe it witharia-label/aria-labelledby. - Update each option’s
aria-pressed/aria-selectedto reflect the active state while clearing the rest. - Reference usage guidance through
aria-describedbyon the group (e.g., “Choose one view”).
Imports
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'Props
| Prop | Type | Default | Description |
|---|---|---|---|
| id * | string | undefined | Unique identifier for the radio button |
| size | 'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs' | 'md' | Size of the radio button |
| disabled | boolean | false | Whether the radio button is disabled |
| value | string | number | boolean | undefined | Value associated with the radio button |
| name | string | undefined | Name attribute for the radio button |
| label | string | undefined | Label text for the radio button |
| onlyIcon | boolean | false | Renders only the icon slot and hides the label text |
HLRadioGroup Props
Content Switchers must be wrapped in an HLRadioGroup, which owns the selected value and applies shared size, width, and theme. These are the radio group props relevant here — see the Radio Group docs for its full API.
| Prop | Type | Default | Description |
|---|---|---|---|
| id * | string | undefined | Unique identifier for the radio group |
| value | string | number | boolean | undefined | The selected value. Bind with v-model:value |
| size | 'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs' | 'md' | Size applied to all switchers in the group |
| width | 'default' | 'equal' | 'full' | 'default' | Width distribution — default fits content, equal splits evenly, full spans the container |
| theme | 'primary' | 'neutral' | 'primary' | Visual theme applied to the switchers (see Theme variants) |
| disabled | boolean | false | Disables every switcher in the group |
Slots
| Name | Description |
|---|---|
icon | Slot for the icon |
default | Slot for the default content |
Emits
| Name | Parameters | Description |
|---|---|---|
@change | (event: Event) | Emitted on the individual switcher when it is selected. Payload is the native change Event. |
Methods
Available on an HLContentSwitcher via a template ref.
| Name | Type | Description |
|---|---|---|
focus | () => void | Focuses the switcher |
blur | () => void | Removes focus from the switcher |