Skip to content
RTL Support: Full
Accessibility: Full
Translations: Not Needed
Migration Guide: Not Needed

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.

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

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

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

vue
<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>
ts
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).

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

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

vue
<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>
vue
<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 needs
  • equal: 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 small
  • full: Content Switchers evenly distribute the container's width between them, with text truncating if needed

Default Width


Equal Width


Full Width


Vue
vue
<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

Pick a view to log events.
Vue
vue
<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" or role="tablist" and describe it with aria-label / aria-labelledby.
  • Update each option’s aria-pressed / aria-selected to reflect the active state while clearing the rest.
  • Reference usage guidance through aria-describedby on the group (e.g., “Choose one view”).

Imports

ts
import { HLContentSwitcher, HLRadioGroup } from '@platform-ui/highrise'

Props

PropTypeDefaultDescription
id *stringundefinedUnique identifier for the radio button
size'lg' | 'md' | 'sm' | 'xs' | '2xs' | '3xs''md'Size of the radio button
disabledbooleanfalseWhether the radio button is disabled
valuestring | number | booleanundefinedValue associated with the radio button
namestringundefinedName attribute for the radio button
labelstringundefinedLabel text for the radio button
onlyIconbooleanfalseRenders 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.

PropTypeDefaultDescription
id *stringundefinedUnique identifier for the radio group
valuestring | number | booleanundefinedThe 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)
disabledbooleanfalseDisables every switcher in the group

Slots

NameDescription
iconSlot for the icon
defaultSlot for the default content

Emits

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

NameTypeDescription
focus() => voidFocuses the switcher
blur() => voidRemoves focus from the switcher