Skip to content

Toggle Group

Shares one pressed state between a row of toggles, one at a time or several.

View source View as Markdown

Toggle Group puts a set of Toggle.Root buttons under one value, so pressing one can unpress the others. Useful for a choice with a handful of options that all fit on screen, like text alignment, and for a row of formatting buttons where several can be on at once.

App.vue
<template>
  <div class="flex flex-col items-start gap-4">
    <Toggle.Group v-model="alignment" aria-label="Text alignment" :class="group">
      <Toggle.Root
        v-for="entry in alignments"
        :key="entry.value"
        :class="toggle"
        :value="entry.value"
      >
        {{ entry.label }}
      </Toggle.Root>
    </Toggle.Group>

    <Toggle.Group
      v-model="formats"
      aria-label="Formatting"
      :class="group"
      :options="{ mode: 'multiple' }"
    >
      <Toggle.Root
        v-for="entry in formatting"
        :key="entry.value"
        :aria-label="entry.label"
        :class="[toggle, entry.glyphClass]"
        :value="entry.value"
      >
        {{ entry.glyph }}
      </Toggle.Root>
    </Toggle.Group>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'
import { Toggle } from '@maas/mirror/vue/Toggle'

const alignment = ref(['left'])
const formats = ref(['bold'])

const alignments = [
  { value: 'left', label: 'Left' },
  { value: 'center', label: 'Center' },
  { value: 'right', label: 'Right' },
]

const formatting = [
  { value: 'bold', label: 'Bold', glyph: 'B', glyphClass: 'font-bold' },
  { value: 'italic', label: 'Italic', glyph: 'I', glyphClass: 'italic' },
  {
    value: 'underline',
    label: 'Underline',
    glyph: 'U',
    glyphClass: 'underline',
  },
]

const group =
  'rounded-[calc(var(--radius-component-md)+0.25rem+1px)] border-surface flex gap-1 border p-1'

const toggle = [
  'inline-flex h-9 min-w-9 items-center justify-center px-3',
  'rounded-component-md border-2 border-[transparent] type-component-sm',
  'text-primary-solid transition-all duration-100 ease-linear',
  'outline-4 outline-transparent focus-visible:focus-ring',
  'hover:bg-primary-subtle',
  'active:bg-primary-subtle-active',
  'data-[state=on]:bg-primary-solid data-[state=on]:text-primary-on-solid',
  'data-[state=on]:hover:bg-primary-solid-hover',
  'data-[state=on]:active:bg-primary-solid-active',
].join(' ')
</script>

Usage guidelines

  • Every Toggle.Root inside a group needs a value, since that is how the group tells one from another. A toggle without one throws rather than joining the group silently.must
  • The group is one tab stop and has no name of its own, so give it an aria-label describing what the toggles have in common.must
  • Where only one option can be on and one always has to be, use Radio instead. A single-select group can be emptied by pressing the toggle that is already on, which a radio group cannot.should