Logo

Radio Group

Native radio group primitives with descriptions, choice cards, fieldset grouping, reactive forms validation, custom styling, and RTL support.

Preview

Usage

TS

import { FrFieldModule } from '@frame-ui-ng/components/field';
import { FrRadioGroupModule } from '@frame-ui-ng/components/radio-group';

HTML

<div frRadioGroup aria-label="Notification channel">
  <label frRadioGroupField>
    <input frRadioGroupItem type="radio" name="channel" value="email" checked />
    <span frFieldLabel>Email</span>
  </label>

  <label frRadioGroupField>
    <input frRadioGroupItem type="radio" name="channel" value="slack" />
    <span frFieldLabel>Slack</span>
  </label>
</div>

Examples

Basic

Use a radio group when users must pick exactly one option from a small set.

Descriptions

Pair radio items with Field content when each option needs supporting explanation.

Choice card

Use the card variant and card primitives when each radio option should render as a larger selection surface.

Fieldset

Use FieldSet and FieldLegend when a group needs a visible question or section heading.

Export schedule

Choose when reports should be generated for your workspace.

Disabled

Disable individual radios when a policy or upstream dependency prevents selecting that value.

Invalid with reactive forms

Use Angular validation to drive invalid styling and error text while keeping each option a native radio input.

Escalation path

Select one owner before saving the workflow.

RTL

Radio rows use logical spacing and native inputs, so labels and controls follow the document direction.

Custom Styling

Scope radio group token overrides to a wrapper when a form section needs a stronger selected state, larger target, or different focus treatment.

Token Inspector

Hover the group, field, radio item, content, label, description, or disabled item to inspect the tokens that shape the radio group pattern.

Design Tokens

Use these CSS custom properties to tune radio group spacing, radio item sizing, checked state, focus ring, invalid state, and disabled opacity.

SCSS

--frame-radio-group-gap: 0.75rem;
--frame-radio-group-horizontal-gap: 1rem;
--frame-radio-group-card-gap: 0.75rem;
--frame-radio-group-card-padding: 1rem;
--frame-radio-group-card-radius: var(--frame-radius-lg);
--frame-radio-group-card-bg: var(--frame-surface);
--frame-radio-group-card-border: var(--frame-border);
--frame-radio-group-card-hover-border: color-mix(in srgb, var(--frame-border) 70%, var(--frame-foreground));
--frame-radio-group-card-checked-border: var(--frame-primary);
--frame-radio-group-card-checked-shadow: 0 0 0 3px color-mix(in srgb, var(--frame-primary) 14%, transparent);
--frame-radio-group-card-disabled-opacity: 0.55;
--frame-radio-group-card-meta-color: var(--frame-muted-foreground);
--frame-radio-group-card-meta-font-size: 0.875rem;
--frame-radio-group-card-meta-font-weight: 600;
--frame-radio-group-item-size: 1rem;
--frame-radio-group-item-bg: var(--frame-surface);
--frame-radio-group-item-border: var(--frame-border);
--frame-radio-group-item-color: var(--frame-primary);
--frame-radio-group-item-hover-border: color-mix(in srgb, var(--frame-border) 72%, var(--frame-foreground));
--frame-radio-group-item-checked-border: var(--frame-primary);
--frame-radio-group-item-checked-bg: var(--frame-surface);
--frame-radio-group-item-dot-size: 0.5rem;
--frame-radio-group-item-focus-shadow: 0 0 0 3px color-mix(in srgb, var(--frame-ring) 32%, transparent);
--frame-radio-group-item-invalid-border: var(--frame-destructive);
--frame-radio-group-item-disabled-opacity: 0.5;
--frame-radio-group-transition-duration: 150ms;
--frame-radio-group-transition-easing: ease;