Skip to content

SelectButton ​

SelectButton is a segmented control: a row of mutually exclusive options with a sliding highlight behind the selected one. It is built on reka-ui's radio group, so it exposes radiogroup / radio semantics and arrow-key navigation.

vue
<script setup lang="ts">
import { ref } from 'vue'
import { SelectButton } from '@myghf/ui'

const view = ref('day')
const options = [
  { label: 'Day', value: 'day' },
  { label: 'Week', value: 'week' },
]
</script>

<template>
  <SelectButton v-model="view" :options="options" aria-label="Calendar view" />
</template>

Examples ​

Segmented options ​

optionLabel / optionValue name the object keys (both default to label / value). The highlight is measured from the checked item and follows selection, resize, and option changes.

View: day

vue
<script setup lang="ts">
import { ref } from 'vue'
import { SelectButton } from '@myghf/ui'

const view = ref('day')
const options = [
  { label: 'Day', value: 'day' },
  { label: 'Week', value: 'week' },
  { label: 'Month', value: 'month' },
]
</script>

<template>
  <div class="grid max-w-md gap-3">
    <SelectButton v-model="view" :options="options" aria-label="Calendar view" />

    <SelectButton
      :model-value="'week'"
      :options="options"
      disabled
      aria-label="Disabled calendar view"
    />

    <p class="text-sm text-muted">View: {{ view }}</p>
  </div>
</template>

Props ​

PropTypeDefaultDescription
modelValueAcceptableValue—Selected value.
optionsRecord<string, unknown>[]—Choices, read via optionLabel / optionValue.
optionLabelstring'label'Key whose value is shown as an option's label.
optionValuestring'value'Key whose value is emitted as an option's value.
disabledbooleanfalseDisables the whole group.

Events ​

EventPayloadDescription
update:modelValueunknownEmitted with the value of the newly selected option.

Slots ​

SelectButton renders no slots. Options are data-only.

Exposed methods ​

None. SelectButton does not call defineExpose.

Accessibility ​

  • reka-ui renders the group with role="radiogroup" and each item with role="radio" + aria-checked, so assistive technology announces it as a single-choice set. Arrow keys move between options.
  • Give the group an accessible name with aria-label or aria-labelledby; it renders no visible label. Extra attributes fall through to the group root.
    vue
    <SelectButton v-model="view" :options="options" aria-label="Calendar view" />
  • The moving highlight is aria-hidden and purely decorative; selection is conveyed by aria-checked, not by the highlight alone.
  • There is no invalid state and no size prop.

Dark mode & RTL ​

  • The track uses bg-surface with a border-border outline and the highlight uses primary-500 with white text, so it adapts to dark mode through the shared tokens.
  • The highlight is positioned from the checked item's physical offsetLeft / offsetTop, which stays correct when the flex row mirrors under RTL — the measured box matches the item's rendered position. Items use symmetric padding and no physical directional utilities.

Released under the MIT License.