---
title: "FlatRadio"
description: "A segmented control for choosing among two to five inline options."
category: Form
status: beta
since: 0.3.4
tags: [select, flat, form, selection, inline]
syncStatus: reviewed
verified: true
---

## Usage

### Basic
:::TuffDemoWrapper{demo="FlatRadioBasicDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const value = ref<'light' | 'dark' | 'auto'>('light')
  </script>

  <template>
    <TxFlatRadio v-model="value">
      <TxFlatRadioItem value="light" label="Light" />
      <TxFlatRadioItem value="dark" label="Dark" />
      <TxFlatRadioItem value="auto" label="Auto" />
    </TxFlatRadio>
  </template>
---
:::

### Disabled
Set `disabled` on the whole group or on single items.
:::TuffDemoWrapper{demo="FlatRadioDisabledDemo" code-lang="vue"}
---
code: |
  <template>
    <TxFlatRadio v-model="value">
      <TxFlatRadioItem value="a" label="Option A" />
      <TxFlatRadioItem value="b" label="Option B" disabled />
      <TxFlatRadioItem value="c" label="Option C" />
    </TxFlatRadio>

    <TxFlatRadio v-model="value" disabled>
      <TxFlatRadioItem value="a" label="Option A" />
      <TxFlatRadioItem value="b" label="Option B" />
    </TxFlatRadio>
  </template>
---
:::

### Sizes
`size` takes `sm`, `md` (default), `lg`, or `xl`.
:::TuffDemoWrapper{demo="FlatRadioSizesDemo" code-lang="vue"}
---
code: |
  <template>
    <TxFlatRadio v-for="size in ['sm', 'md', 'lg', 'xl']" :key="size" v-model="value" :size="size">
      <TxFlatRadioItem value="a" label="Option A" />
      <TxFlatRadioItem value="b" label="Option B" />
      <TxFlatRadioItem value="c" label="Option C" />
    </TxFlatRadio>
  </template>
---
:::

### Icons
`icon` takes an icon class, such as a UnoCSS icon.
:::TuffDemoWrapper{demo="FlatRadioIconDemo" code-lang="vue"}
---
code: |
  <template>
    <TxFlatRadio v-model="view">
      <TxFlatRadioItem value="grid" icon="i-carbon-grid" label="Grid" />
      <TxFlatRadioItem value="list" icon="i-carbon-list" label="List" />
      <TxFlatRadioItem value="kanban" icon="i-carbon-column" label="Kanban" />
    </TxFlatRadio>
  </template>
---
:::

### Bordered
:::TuffDemoWrapper{demo="FlatRadioBorderedDemo" code-lang="vue"}
---
code: |
  <template>
    <TxFlatRadio v-model="value" bordered>
      <TxFlatRadioItem value="a" label="Option A" />
      <TxFlatRadioItem value="b" label="Option B" />
      <TxFlatRadioItem value="c" label="Option C" />
    </TxFlatRadio>
  </template>
---
:::

### Multiple
With `multiple`, the value is an array and items toggle like checkboxes, without the thumb.
:::TuffDemoWrapper{demo="FlatRadioMultipleDemo" code-lang="vue"}
---
code: |
  <script setup lang="ts">
  import { ref } from 'vue'

  const value = ref(['mention', 'reply'])
  </script>

  <template>
    <TxFlatRadio v-model="value" multiple>
      <TxFlatRadioItem value="mention" label="Mention" icon="i-carbon-at" />
      <TxFlatRadioItem value="reply" label="Reply" icon="i-carbon-reply" />
      <TxFlatRadioItem value="archive" label="Archive" icon="i-carbon-archive" />
      <TxFlatRadioItem value="mute" label="Mute" icon="i-carbon-volume-mute" />
    </TxFlatRadio>
  </template>
---
:::

### Keyboard Navigation
Once the container has focus, it responds to the keys below.
:::TuffDemoWrapper{demo="FlatRadioKeyboardDemo" code-lang="vue"}
---
code: |
  <template>
    <TxFlatRadio v-model="single">
      <TxFlatRadioItem value="overview" label="Overview" />
      <TxFlatRadioItem value="activity" label="Activity" />
      <TxFlatRadioItem value="settings" label="Settings" />
    </TxFlatRadio>

    <TxFlatRadio v-model="channels" multiple>
      <TxFlatRadioItem value="email" label="Email" />
      <TxFlatRadioItem value="push" label="Push" />
      <TxFlatRadioItem value="sms" label="SMS" />
    </TxFlatRadio>
  </template>
---
:::

| Key | Behavior |
|-----|----------|
| `→` / `↓` | Next enabled item (wraps) |
| `←` / `↑` | Previous enabled item (wraps) |
| `Home` | First enabled item |
| `End` | Last enabled item |
| `Enter` / `Space` | Toggles the current item in `multiple` mode |

### Best Practices

- Use for two to five short options that benefit from side-by-side comparison (labels don't wrap); use `TxSelect` for more.
- Use `xl` when the control is the primary choice on screen; keep the default `md` inline and in toolbars.
- Don't bold custom slot content only when selected: every item already carries the selected weight, and extra bold reflows the row.
- Use `multiple` only for independent values; otherwise use switches or checkboxes.
- Keep `value` stable across renders: the parent registers items by value for thumb placement and keyboard order.

## API Reference

### TxFlatRadio

#### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `modelValue` / `v-model` | `string \| number \| (string \| number)[]` | *required* | A single value, or an array in `multiple` mode. |
| `multiple` | `boolean` | `false` | Multi-select: items toggle like checkboxes and the thumb is hidden. |
| `disabled` | `boolean` | `false` | Disables the whole group, removing it from the tab order and blocking changes. |
| `size` | `'sm' \| 'md' \| 'lg' \| 'xl'` | `'md'` | Size. |
| `bordered` | `boolean` | `false` | Adds an outer border. |

#### Events

| Event | Params | Description |
|-------|--------|-------------|
| `update:modelValue` | `(value: string \| number \| (string \| number)[]) => void` | Fires with the new value after a selection change. |
| `change` | `(value: string \| number \| (string \| number)[]) => void` | Fires together with `update:modelValue`. |

#### Slots

| Slot | Description |
|------|-------------|
| `default` | `TxFlatRadioItem` children. |

### TxFlatRadioItem

#### Props

| Prop | Type | Default | Description |
|------|------|---------|-------------|
| `value` | `string \| number` | *required* | The item's value, registered with the parent. |
| `label` | `string` | - | Text shown when there is no default slot. |
| `icon` | `string` | - | Icon class used when there is no `icon` slot. |
| `disabled` | `boolean` | `false` | Disables the item and skips it in keyboard navigation. |

#### Slots

| Slot | Description |
|------|-------------|
| `default` | Custom content, replacing `label`. |
| `icon` | Custom icon, replacing `icon`. |

## Overview

- Single mode renders `role="radiogroup"` with `role="radio"` items; `multiple` renders `role="group"` with `role="checkbox"` items.
- Only the container is tabbable; items keep `tabindex="-1"`. Name the group with nearby field text or an external label.
- In single mode the arrow keys select directly; in `multiple` mode they only move focus, and Enter / Space toggles.
- The thumb never scales. It lands in place on mount, resize, and item registration, glides to a new selection, and never leaves the track.
- A press scales the label and icon, never the item box.
- Under reduced motion, the thumb lands in place and the press scale is dropped; the fade stays.

## Technologies

- The thumb runs on the glide material of the shared `useJellyIndicator` (as in `TxTabs`, `TxTabBar`, and `TxSidebarNav`), writing `transform`, `width`, and `opacity` each frame without re-rendering.
- Source: `packages/tuffex/packages/components/src/flat-radio/`.

<TuffDocSourceLink />

## Customization

| CSS variable | Used for |
|--------------|----------|
| `--tx-flat-radio-track-bg` | Track fill; defaults to `--tx-fill-color`. |
| `--tx-flat-radio-indicator-bg` | Thumb and multi-select item fill; defaults to `--tx-surface-raised`. |
| `--tx-flat-radio-indicator-shadow` | Thumb shadow. |
