Components

Toggle Group

Source
Select one or multiple values from a connected set of toggles.
Install with the CLI
npx @vyui/cli add toggle-group

Overview

VyToggleGroup renders connected toggle buttons from an items array. It supports single or multiple selection, controlled and uncontrolled values, horizontal or vertical layout, disabled items, icons, labels, and a custom item slot.

Usage

Use type="single" with a scalar v-model. Primitive strings and numbers are normalized into matching labels and values.

<script setup lang="ts">
import { ref } from 'vue'
import { VyToggleGroup } from '@vyui/kit'

const alignment = ref('center')
const items = [
  { label: 'Left', value: 'left', icon: 'i-lucide-align-left' },
  { label: 'Center', value: 'center', icon: 'i-lucide-align-center' },
  { label: 'Right', value: 'right', icon: 'i-lucide-align-right' },
]
</script>

<template>
  <VyToggleGroup v-model="alignment" :items="items" />
</template>

Multiple selection

Use an array model with type="multiple". Tapping an item adds or removes its value.

<script setup lang="ts">
import { ref } from 'vue'
import { VyToggleGroup } from '@vyui/kit'

const formatting = ref<string[]>(['bold'])
const items = [
  { label: 'Bold', value: 'bold' },
  { label: 'Italic', value: 'italic' },
  { label: 'Underline', value: 'underline', disabled: true },
]
</script>

<template>
  <VyToggleGroup
    v-model="formatting"
    type="multiple"
    :items="items"
    color="secondary"
    variant="soft"
  />
</template>

Custom items

The default slot replaces an entire item's built-in icon and label. It receives the normalized item, its index, and a resolved hex color for custom SVG icons.

<VyToggleGroup v-model="density" :items="items">
  <template #default="{ item, iconColor }">
    <VyIcon :name="item.icon" :color="iconColor" />
    <text>{{ item.label }}</text>
  </template>
</VyToggleGroup>

Features and behavior

  • single mode stores one string or number. Tapping the selected item again clears the runtime value.
  • multiple mode stores an array and toggles each tapped value independently.
  • Use modelValue or v-model for controlled state, or defaultValue for an uncontrolled initial selection.
  • String and number items become { value: item, label: String(item) }.
  • Object items use value, falling back to label; their label falls back to String(value).
  • Object items should provide at least value or label, and every resolved value should be unique because it is also used as the render key.
  • Group-level disabled disables every item. An item's disabled field disables only that item.
  • orientation changes connected-border layout; it does not reorder the supplied items.

Toggle group item

FieldTypeDefaultDescription
labelstringString form of the resolved valueVisible item text.
iconstringundefinedLeading Iconify icon name.
valuestring | numberlabelSelection value and render key.
disabledbooleanfalsePrevents interaction for this item.
[key: string]anyAdditional application data retained on the normalized item and exposed to the slot.

The items array also accepts primitive strings and numbers.

Props

PropTypeDefaultDescription
type'single' | 'multiple''single'Whether one value or multiple values can be selected.
modelValuestring | number | Array<string | number>undefinedControlled selection; use an array for multiple mode.
defaultValuestring | number | Array<string | number>Single: undefined; multiple: []Initial uncontrolled selection.
itemsArray<ToggleGroupItem | string | number>undefinedItems to normalize and render.
disabledbooleanfalseDisables every item in the group.
colorColor'primary'Semantic selected-state color.
variant'outline' | 'soft' | 'subtle''outline'Item surface, border, and selected-state treatment.
size'sm' | 'md' | 'lg' | 'xl''md'Item padding, text size, gap, and icon size.
orientation'horizontal' | 'vertical''horizontal'Connected row or column layout.
classanyundefinedClasses merged onto the group root.
uiPartial<Record<ToggleGroupSlot, any>>undefinedPer-instance theme slot overrides.

Color defaults to primary, secondary, success, info, warning, error, or neutral, and supports consumer registry extensions.

Keep type coherent with the value shape: scalar for single, array for multiple. The kit wrapper always defaults an omitted type to single.

Emits

EventPayloadDescription
update:modelValuestring | number | Array<string | number>Emitted after selection changes. In single mode, deselecting the active item produces undefined at runtime.

Slots

SlotPropsDescription
default{ item, index, iconColor }Replaces the built-in icon and label for every item. item is normalized and iconColor is a resolved hex string.

Styling and theming

Override globally through appConfig.ui.toggleGroup or locally with ui.

UI slotPurpose
rootGroup direction, wrapping, and connected overlap.
itemToggle layout, spacing, borders, surfaces, rounding, and disabled state.
leadingIconBuilt-in icon size and state-dependent foreground.
labelBuilt-in label truncation and state-dependent foreground.

The theme combines color, variant, size, and orientation.

VariantAppearance
outlineWhite items with neutral borders; selected items gain a semantic border and light surface.
softNeutral resting surface; selected items gain a stronger light semantic surface.
subtleLighter neutral border than outline; selected items use a soft semantic border and surface.

Horizontal groups use a wrapping row, overlap adjacent borders by one pixel, and round the first and last inline edges. Vertical groups use a column, overlap horizontal borders, round the top and bottom items, and make each item full width.

Accessibility

Each item is exposed by the core primitive as a focusable native button and announces pressed or not pressed. Disabled groups and items use the disabled trait.

The kit item shape does not currently forward an accessibility-label to individual toggle roots. Prefer visible, descriptive labels. Icon-only groups do not have a kit-level per-item labeling API today, so treat them as an accessibility limitation and test them with VoiceOver and TalkBack. The group root itself does not add a native group role, and the current accessibility layer does not bridge these semantics to web ARIA.

Platform notes

  • Items respond to Lynx tap events through the @vyui/core toggle primitives.
  • Lynx SVG does not inherit currentColor; built-in icons receive a resolved hex color, and custom slots receive the same value as iconColor.
  • Text color classes are applied directly to leadingIcon and label because CSS inheritance is disabled in the Lynx build.
  • The default theme is light-mode-only.
  • Toggle for one independent pressed-state control.
  • Radio Group for a required single-choice form field.
  • Switch for an immediately applied binary setting.