# Radio Button Group

Use `ui-radio-button-group` when users need to choose exactly one option from a small set and a button-like segmented presentation fits better than classic radios. It works well for view switches, density controls, mode selectors, and compact settings choices.

## Import
```ts
import { RadioButtonGroupComponent, type RadioButtonItem } from 'ui';
```

## Basic single-choice groups
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem } from 'ui';

@Component({
  selector: 'app-radio-button-group-basic-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;width:100%;max-width:44rem"
    >
      <ui-radio-button-group
        label="View mode"
        helpText="A compact single-choice switch for common modes."
        [items]="viewItems"
        [(ngModel)]="viewMode"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Delivery speed"
        helpText="Button-like radios work well when there are only a few mutually exclusive choices."
        [items]="deliveryItems"
        [(ngModel)]="delivery"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class RadioButtonGroupBasicDemoComponent {
  protected viewMode = 'board';
  protected delivery = 'standard';

  protected readonly viewItems: RadioButtonItem[] = [
    { id: 'board', label: 'Board', value: 'board' },
    { id: 'list', label: 'List', value: 'list' },
    { id: 'timeline', label: 'Timeline', value: 'timeline' },
  ];

  protected readonly deliveryItems: RadioButtonItem[] = [
    { id: 'standard', label: 'Standard', value: 'standard' },
    { id: 'express', label: 'Express', value: 'express' },
    { id: 'overnight', label: 'Overnight', value: 'overnight' },
  ];
}
```

## Filled appearance
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem, type Variant } from 'ui';

@Component({
  selector: 'app-radio-button-group-filled-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;align-items:flex-start;gap:0.75rem;width:100%">
      @for (variant of variants; track variant) {
        <ui-radio-button-group
          [label]="getLabel(variant)"
          [items]="items"
          [variant]="variant"
          appearance="filled"
          [(ngModel)]="selection[variant]"
          [ngModelOptions]="{ standalone: true }"
        />
      }
    </div>
  `,
})
export class RadioButtonGroupFilledDemoComponent {
  protected readonly variants: Variant[] = [
    'primary',
    'secondary',
    'success',
    'warning',
    'danger',
    'info',
  ];

  protected readonly selection: Record<Variant, string> = {
    primary: 'comfortable',
    secondary: 'comfortable',
    success: 'comfortable',
    warning: 'comfortable',
    danger: 'comfortable',
    info: 'comfortable',
  };

  protected readonly items: RadioButtonItem[] = [
    { id: 'compact', label: 'Compact', value: 'compact' },
    { id: 'comfortable', label: 'Comfortable', value: 'comfortable' },
    { id: 'spacious', label: 'Spacious', value: 'spacious' },
  ];

  protected getLabel(variant: Variant): string {
    return `${variant[0].toUpperCase()}${variant.slice(1)} filled`;
  }
}
```

## Tint appearance
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem, type Variant } from 'ui';

@Component({
  selector: 'app-radio-button-group-tint-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;align-items:flex-start;gap:0.75rem;width:100%">
      @for (variant of variants; track variant) {
        <ui-radio-button-group
          [label]="getLabel(variant)"
          [items]="items"
          [variant]="variant"
          appearance="tint"
          [(ngModel)]="selection[variant]"
          [ngModelOptions]="{ standalone: true }"
        />
      }
    </div>
  `,
})
export class RadioButtonGroupTintDemoComponent {
  protected readonly variants: Variant[] = [
    'primary',
    'secondary',
    'success',
    'warning',
    'danger',
    'info',
  ];

  protected readonly selection: Record<Variant, string> = {
    primary: 'comfortable',
    secondary: 'comfortable',
    success: 'comfortable',
    warning: 'comfortable',
    danger: 'comfortable',
    info: 'comfortable',
  };

  protected readonly items: RadioButtonItem[] = [
    { id: 'compact', label: 'Compact', value: 'compact' },
    { id: 'comfortable', label: 'Comfortable', value: 'comfortable' },
    { id: 'spacious', label: 'Spacious', value: 'spacious' },
  ];

  protected getLabel(variant: Variant): string {
    return `${variant[0].toUpperCase()}${variant.slice(1)} tint`;
  }
}
```

## Outline appearance
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem, type Variant } from 'ui';

@Component({
  selector: 'app-radio-button-group-outline-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;align-items:flex-start;gap:0.75rem;width:100%">
      @for (variant of variants; track variant) {
        <ui-radio-button-group
          [label]="getLabel(variant)"
          [items]="items"
          [variant]="variant"
          appearance="outline"
          [(ngModel)]="selection[variant]"
          [ngModelOptions]="{ standalone: true }"
        />
      }
    </div>
  `,
})
export class RadioButtonGroupOutlineDemoComponent {
  protected readonly variants: Variant[] = [
    'primary',
    'secondary',
    'success',
    'warning',
    'danger',
    'info',
  ];

  protected readonly selection: Record<Variant, string> = {
    primary: 'comfortable',
    secondary: 'comfortable',
    success: 'comfortable',
    warning: 'comfortable',
    danger: 'comfortable',
    info: 'comfortable',
  };

  protected readonly items: RadioButtonItem[] = [
    { id: 'compact', label: 'Compact', value: 'compact' },
    { id: 'comfortable', label: 'Comfortable', value: 'comfortable' },
    { id: 'spacious', label: 'Spacious', value: 'spacious' },
  ];

  protected getLabel(variant: Variant): string {
    return `${variant[0].toUpperCase()}${variant.slice(1)} outline`;
  }
}
```

## Subtle appearance
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem, type Variant } from 'ui';

@Component({
  selector: 'app-radio-button-group-subtle-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;align-items:flex-start;gap:0.75rem;width:100%">
      @for (variant of variants; track variant) {
        <ui-radio-button-group
          [label]="getLabel(variant)"
          [items]="items"
          [variant]="variant"
          appearance="subtle"
          [(ngModel)]="selection[variant]"
          [ngModelOptions]="{ standalone: true }"
        />
      }
    </div>
  `,
})
export class RadioButtonGroupSubtleDemoComponent {
  protected readonly variants: Variant[] = [
    'primary',
    'secondary',
    'success',
    'warning',
    'danger',
    'info',
  ];

  protected readonly selection: Record<Variant, string> = {
    primary: 'comfortable',
    secondary: 'comfortable',
    success: 'comfortable',
    warning: 'comfortable',
    danger: 'comfortable',
    info: 'comfortable',
  };

  protected readonly items: RadioButtonItem[] = [
    { id: 'compact', label: 'Compact', value: 'compact' },
    { id: 'comfortable', label: 'Comfortable', value: 'comfortable' },
    { id: 'spacious', label: 'Spacious', value: 'spacious' },
  ];

  protected getLabel(variant: Variant): string {
    return `${variant[0].toUpperCase()}${variant.slice(1)} subtle`;
  }
}
```

## Transparent appearance
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem, type Variant } from 'ui';

@Component({
  selector: 'app-radio-button-group-transparent-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div style="display:flex;flex-wrap:wrap;align-items:flex-start;gap:0.75rem;width:100%">
      @for (variant of variants; track variant) {
        <ui-radio-button-group
          [label]="getLabel(variant)"
          [items]="items"
          [variant]="variant"
          appearance="transparent"
          [(ngModel)]="selection[variant]"
          [ngModelOptions]="{ standalone: true }"
        />
      }
    </div>
  `,
})
export class RadioButtonGroupTransparentDemoComponent {
  protected readonly variants: Variant[] = [
    'primary',
    'secondary',
    'success',
    'warning',
    'danger',
    'info',
  ];

  protected readonly selection: Record<Variant, string> = {
    primary: 'comfortable',
    secondary: 'comfortable',
    success: 'comfortable',
    warning: 'comfortable',
    danger: 'comfortable',
    info: 'comfortable',
  };

  protected readonly items: RadioButtonItem[] = [
    { id: 'compact', label: 'Compact', value: 'compact' },
    { id: 'comfortable', label: 'Comfortable', value: 'comfortable' },
    { id: 'spacious', label: 'Spacious', value: 'spacious' },
  ];

  protected getLabel(variant: Variant): string {
    return `${variant[0].toUpperCase()}${variant.slice(1)} transparent`;
  }
}
```

## Icons, size, and emphasis
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem } from 'ui';

@Component({
  selector: 'app-radio-button-group-icons-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;width:100%;max-width:48rem"
    >
      <ui-radio-button-group
        label="Channel"
        helpText="Icons help when the choices are recognizable and only a few."
        [items]="channelItems"
        variant="primary"
        appearance="tint"
        [(ngModel)]="channel"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Theme preset"
        helpText="Shape and size can reinforce a more prominent segmented control."
        [items]="themeItems"
        size="large"
        shape="rounded"
        appearance="outline"
        [(ngModel)]="theme"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class RadioButtonGroupIconsDemoComponent {
  protected channel = 'email';
  protected theme = 'balanced';

  protected readonly channelItems: RadioButtonItem[] = [
    { id: 'email', label: 'Email', value: 'email', icon: 'mail' },
    { id: 'chat', label: 'Chat', value: 'chat', icon: 'chat' },
    { id: 'teams', label: 'Call', value: 'call', icon: 'call' },
  ];

  protected readonly themeItems: RadioButtonItem[] = [
    { id: 'balanced', label: 'Balanced', value: 'balanced', icon: 'apps' },
    { id: 'focus', label: 'Focus', value: 'focus', icon: 'panel_left' },
    { id: 'review', label: 'Review', value: 'review', icon: 'comment' },
  ];
}
```

## Shapes
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem } from 'ui';

@Component({
  selector: 'app-radio-button-group-shapes-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;width:100%;max-width:56rem"
    >
      <ui-radio-button-group
        label="Rounded"
        helpText="Default shape for most segmented choices."
        [items]="viewItems"
        shape="rounded"
        variant="primary"
        appearance="tint"
        [(ngModel)]="roundedValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Square"
        helpText="Useful when the surrounding UI uses sharper edges."
        [items]="viewItems"
        shape="square"
        appearance="outline"
        [(ngModel)]="squareValue"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Circular"
        helpText="Works best with short, icon-led choices."
        [items]="toolItems"
        shape="circular"
        appearance="tint"
        [(ngModel)]="circularValue"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class RadioButtonGroupShapesDemoComponent {
  protected roundedValue = 'board';
  protected squareValue = 'list';
  protected circularValue = 'mail';

  protected readonly viewItems: RadioButtonItem[] = [
    { id: 'board', label: 'Board', value: 'board' },
    { id: 'list', label: 'List', value: 'list' },
    { id: 'timeline', label: 'Timeline', value: 'timeline' },
  ];

  protected readonly toolItems: RadioButtonItem[] = [
    { id: 'mail', label: 'Mail', value: 'mail', icon: 'mail' },
    { id: 'chat', label: 'Chat', value: 'chat', icon: 'chat' },
    { id: 'call', label: 'Call', value: 'call', icon: 'call' },
  ];
}
```

## Disabled, readonly, and required states
```ts
import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { RadioButtonGroupComponent, type RadioButtonItem } from 'ui';

@Component({
  selector: 'app-radio-button-group-states-demo',
  standalone: true,
  imports: [FormsModule, RadioButtonGroupComponent],
  template: `
    <div
      style="display:grid;grid-template-columns:repeat(auto-fit,minmax(16rem,1fr));gap:1rem;width:100%;max-width:48rem"
    >
      <ui-radio-button-group
        label="Plan"
        helpText="Per-option disabled state is useful when some choices are unavailable."
        [items]="planItems"
        [(ngModel)]="plan"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Readonly decision"
        helpText="Readonly keeps the current value visible without allowing changes."
        [items]="decisionItems"
        [readonly]="true"
        [(ngModel)]="decision"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Required approval"
        helpText="Required groups still need a clear visible prompt."
        [items]="approvalItems"
        [required]="true"
        [(ngModel)]="approval"
        [ngModelOptions]="{ standalone: true }"
      />

      <ui-radio-button-group
        label="Disabled mode"
        helpText="Disabled removes the whole control from interaction."
        [items]="decisionItems"
        [disabled]="true"
        [(ngModel)]="disabledMode"
        [ngModelOptions]="{ standalone: true }"
      />
    </div>
  `,
})
export class RadioButtonGroupStatesDemoComponent {
  protected plan = 'team';
  protected decision = 'approved';
  protected approval = 'owner';
  protected disabledMode = 'approved';

  protected readonly planItems: RadioButtonItem[] = [
    { id: 'solo', label: 'Solo', value: 'solo' },
    { id: 'team', label: 'Team', value: 'team' },
    { id: 'enterprise', label: 'Enterprise', value: 'enterprise', disabled: true },
  ];

  protected readonly decisionItems: RadioButtonItem[] = [
    { id: 'approved', label: 'Approved', value: 'approved' },
    { id: 'changes', label: 'Needs changes', value: 'changes' },
    { id: 'blocked', label: 'Blocked', value: 'blocked' },
  ];

  protected readonly approvalItems: RadioButtonItem[] = [
    { id: 'owner', label: 'Owner', value: 'owner' },
    { id: 'legal', label: 'Legal', value: 'legal' },
    { id: 'finance', label: 'Finance', value: 'finance' },
  ];
}
```

## Settings panel composition
```ts
import { Component, computed } from '@angular/core';
import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
import { RadioButtonGroupComponent } from 'ui';

@Component({
  selector: 'app-radio-button-group-settings-panel-demo',
  standalone: true,
  imports: [ReactiveFormsModule, RadioButtonGroupComponent],
  template: `
    <div
      style="display:flex;flex-direction:column;gap:1rem;width:100%;max-width:44rem;padding:1rem;border:1px solid var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background-rest)"
    >
      <div style="font-size:0.9375rem;font-weight:600">Publishing settings</div>

      <div
        style="display:grid;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));gap:1rem;width:100%"
      >
        <ui-radio-button-group
          label="Audience"
          [formControl]="settingsForm.controls.audience"
          [items]="audienceItems"
        />

        <ui-radio-button-group
          label="Review mode"
          [formControl]="settingsForm.controls.reviewMode"
          [items]="reviewModeItems"
          orientation="vertical"
        />
      </div>

      <div
        style="display:flex;flex-wrap:wrap;gap:1rem;align-items:center;padding:0.875rem 1rem;border:1px dashed var(--color-neutral-stroke-rest);border-radius:1rem;background:var(--color-neutral-background2-rest)"
      >
        <span style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)"
          >Audience: <strong>{{ summary().audience }}</strong></span
        >
        <span style="font-size:0.8125rem;color:var(--color-neutral-foreground2-rest)"
          >Review: <strong>{{ summary().reviewMode }}</strong></span
        >
      </div>
    </div>
  `,
})
export class RadioButtonGroupSettingsPanelDemoComponent {
  protected readonly audienceItems = [
    { id: 'team', label: 'Team', value: 'team' },
    { id: 'clients', label: 'Clients', value: 'clients' },
    { id: 'public', label: 'Public', value: 'public' },
  ];

  protected readonly reviewModeItems = [
    { id: 'summary', label: 'Summary only', value: 'summary' },
    { id: 'inline', label: 'Inline comments', value: 'inline' },
    { id: 'strict', label: 'Strict approval', value: 'strict' },
  ];

  protected readonly settingsForm = new FormGroup({
    audience: new FormControl('team', { nonNullable: true }),
    reviewMode: new FormControl('inline', { nonNullable: true }),
  });

  protected readonly summary = computed(() => ({
    audience: this.settingsForm.controls.audience.getRawValue(),
    reviewMode: this.settingsForm.controls.reviewMode.getRawValue(),
  }));
}
```

## Accessibility

### Radiogroup semantics
`ui-radio-button-group` renders a `radiogroup` and each option exposes radio semantics through button-based items with `role="radio"` and `aria-checked`.

### Keyboard behavior
Keyboard handling follows the group orientation.

| Key | Action |
| --- | --- |
| Tab / Shift+Tab | Moves focus into or out of the group. |
| ArrowLeft / ArrowRight | Moves selection in horizontal groups. |
| ArrowUp / ArrowDown | Moves selection in vertical groups. |

### Labels and disabled options
Use a clear group label because the visible label is also the primary accessible name of the `radiogroup`. Disabled options should remain understandable rather than disappearing from the choice set.
