Radio Card
Radio cards for selection with enhanced visual presentation
Default
Radio cards arranged vertically in a group, each with an icon, title, and description.
<template>
<HLRadioGroup :value="value">
<HLSpace vertical>
<HLRadioCard
@change="handleChange"
value="card1"
title="Business plan"
description="Includes up to 20 users, 40GB individual data and access to all features."
>
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
<HLRadioCard
@change="handleChange"
value="card2"
title="Business plan"
description="Includes up to 20 users, 40GB individual data and access to all features."
>
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
</HLSpace>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLRadioCard, HLRadioGroup, HLSpace } from '@platform-ui/highrise'
import { LayersThree01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('')
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
}
</script>Without Icon
A radio card rendered with only a title and description, omitting the icon slot.
Business plan
Includes up to 20 users, 40GB individual data and access to all features.
<template>
<HLRadioGroup :value="value">
<HLRadioCard
@change="handleChange"
value="card1"
title="Business plan"
description="Includes up to 20 users, 40GB individual data and access to all features."
/>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLRadioCard, HLRadioGroup } from '@platform-ui/highrise'
import { ref } from 'vue'
const value = ref('')
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
}
</script>Without Description
A radio card with an icon and title but no description text.
<template>
<HLRadioGroup :value="value">
<HLRadioCard @change="handleChange" value="card1" title="Business plan">
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLRadioCard, HLRadioGroup } from '@platform-ui/highrise'
import { LayersThree01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('')
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
}
</script>Compact Mode
The compact prop reduces the radio card's padding and spacing for denser layouts.
<template>
<HLRadioGroup :value="value">
<HLRadioCard
@change="handleChange"
value="card1"
title="Business plan"
description="Includes up to 20 users, 40GB individual data and access to all features."
compact
>
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLRadioCard, HLRadioGroup } from '@platform-ui/highrise'
import { LayersThree01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('')
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
}
</script>Custom Content
The default slot renders arbitrary content inside the radio card in place of the description.
<template>
<HLRadioGroup :value="value">
<HLSpace vertical>
<HLRadioCard @change="handleChange" value="custom1" title="Business Plan">
<div class="flex flex-col gap-4">
<div class="flex items-center gap-4">
<img src="https://api.dicebear.com/9.x/icons/svg?seed=plan" alt="Business icon" width="48" height="48" class="w-12 h-12 rounded-lg" />
<div class="flex flex-col">
<span class="text-lg font-semibold">$99/month</span>
<span class="text-sm text-gray-500">Billed annually</span>
</div>
</div>
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-primary-500"></span>
<span class="text-sm">Unlimited team members</span>
</div>
<div class="flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-primary-500"></span>
<span class="text-sm">Advanced analytics</span>
</div>
<div class="flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-primary-500"></span>
<span class="text-sm">24/7 priority support</span>
</div>
</div>
</div>
</HLRadioCard>
<HLRadioCard @change="handleChange" value="custom2" title="Enterprise Plan">
<div class="flex flex-col gap-4">
<div class="flex items-center gap-4">
<img src="https://api.dicebear.com/9.x/icons/svg?seed=plan" alt="Enterprise icon" width="48" height="48" class="w-12 h-12 rounded-lg" />
<div class="flex flex-col">
<span class="text-lg font-semibold">$299/month</span>
<span class="text-sm text-gray-500">Billed annually</span>
</div>
</div>
<div class="flex flex-col gap-2">
<div class="flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-primary-500"></span>
<span class="text-sm">Custom integrations</span>
</div>
<div class="flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-primary-500"></span>
<span class="text-sm">Dedicated account manager</span>
</div>
<div class="flex items-center gap-2">
<span class="w-2 h-2 rounded-full bg-primary-500"></span>
<span class="text-sm">SLA guarantees</span>
</div>
</div>
</div>
</HLRadioCard>
</HLSpace>
</HLRadioGroup>
</template><script setup lang="ts">
import { ref } from 'vue'
import { HLRadioCard, HLRadioGroup, HLSpace } from '@platform-ui/highrise'
const value = ref('')
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
}
</script>Custom Icon Size
The iconSize prop overrides the default icon dimensions on the radio card.
<template>
<HLRadioGroup :value="value">
<HLSpace vertical>
<HLRadioCard
@change="handleChange"
value="custom1"
title="Business Plan"
iconSize="48px"
description="Includes up to 20 users, 40GB individual data and access to all features."
>
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
</HLSpace>
</HLRadioGroup>
</template>
<script setup lang="ts">
import { HLRadioCard, HLRadioGroup, HLSpace } from '@platform-ui/highrise'
import { LayersThree01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('')
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
}
</script>Event Testing
This example logs the events the radio card emits as you select an option. @change fires with the native event (read the selected value from event.target.value), and @checked fires with the card's boolean checked state.
Event Log:
<template>
<HLRadioGroup :value="value">
<HLSpace vertical>
<HLRadioCard
value="card1"
title="Business plan"
description="Includes up to 20 users, 40GB individual data and access to all features."
@change="handleChange"
@checked="val => addEventLog('@checked → ' + val)"
>
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
<HLRadioCard
value="card2"
title="Enterprise plan"
description="Includes unlimited users, dedicated support, and SLA guarantees."
@change="handleChange"
@checked="val => addEventLog('@checked → ' + val)"
>
<template #icon>
<LayersThree01Icon />
</template>
</HLRadioCard>
</HLSpace>
</HLRadioGroup>
<div class="text-sm">
<p class="font-bold mb-2">Event Log:</p>
<div v-if="eventLog.length === 0" class="text-gray-500">No events logged yet. Select a card above.</div>
<div v-for="(log, index) in eventLog" :key="index" class="text-gray-700">{{ log.timestamp }}: {{ log.event }}</div>
</div>
</template>
<script setup lang="ts">
import { HLRadioCard, HLRadioGroup, HLSpace } from '@platform-ui/highrise'
import { LayersThree01Icon } from '@gohighlevel/ghl-icons/24/outline'
import { ref } from 'vue'
const value = ref('')
const eventLog = ref<{ event: string; timestamp: string }[]>([])
const addEventLog = (event: string) => {
eventLog.value.unshift({ event, timestamp: new Date().toLocaleTimeString() })
if (eventLog.value.length > 5) {
eventLog.value.pop()
}
}
const handleChange = (e: Event) => {
value.value = (e.target as HTMLInputElement).value
addEventLog('@change → ' + (e.target as HTMLInputElement).value)
}
</script>Accessibility
- Give each radio an
idtied to its visible label and share anameso only one option is selectable. - Reflect the checked option with
aria-checked/aria-disabledand mirror helper text througharia-describedby.
Imports
import { HLRadioCard, HLRadioGroup } from '@platform-ui/highrise'Props
| Name | Type | Default | Description |
|---|---|---|---|
| id | string | Auto (hr-radio-card-*) | The id of the element. Generated automatically when omitted. |
| title | string | undefined | Title text for the radio card |
| description | string | undefined | Description text for the radio card |
| value | string | undefined | Value for the radio card |
| disabled | boolean | false | Whether the radio card is disabled, if disabled is passed to the HLRadioGroup this will be taken priority |
| compact | boolean | false | Whether to use compact mode |
| width | number | undefined | undefined | Custom width for the radio card |
| checked | boolean | undefined | undefined | Whether the radio is checked |
| iconSize | string | 32px | Size of the icon |
Emits
| Name | Parameters | Description |
|---|---|---|
@change | (event: Event) => void | When selection changes |
@checked | (event: Boolean) => void | When the radio is checked |
Slots
| Name | Parameters | Description |
|---|---|---|
| icon | () | Custom icon content |
| default | () | Default slot for custom content |