Use the directive on native radio inputs and pair it with kui-field for group label, hint, and error wiring.

radio.ts
import { KuiField, KuiRadio } from '@kikita-labs/ui';

Share a native name across radio inputs to make the choice mutually exclusive. Keep a native label around each option.

Choose a billing plan

<kui-field label="Plan" hint="Choose a billing plan">
  <div role="radiogroup" class="radio-group" aria-label="Plan">
    <label class="radio-option">
      <input
        kuiRadio
        type="radio"
        name="plan"
        value="starter"
        [checked]="plan() === 'starter'"
        (change)="plan.set('starter')"
      />
      <span>Starter</span>
    </label>
    <label class="radio-option">
      <input
        kuiRadio
        type="radio"
        name="plan"
        value="pro"
        [checked]="plan() === 'pro'"
        (change)="plan.set('pro')"
      />
      <span>Pro</span>
    </label>
  </div>
</kui-field>

Match radio size to surrounding field density and text scale.

<div class="radio-size-example">
  <label class="radio-option">
    <input kuiRadio type="radio" name="radio-size-xs" size="xs" checked />
    <span>Extra small</span>
  </label>
  <label class="radio-option">
    <input kuiRadio type="radio" name="radio-size-sm" size="sm" checked />
    <span>Small</span>
  </label>
  <label class="radio-option">
    <input kuiRadio type="radio" name="radio-size-md" size="md" checked />
    <span>Medium</span>
  </label>
  <label class="radio-option">
    <input kuiRadio type="radio" name="radio-size-lg" size="lg" checked />
    <span>Large</span>
  </label>
</div>

Disable individual options inside a radio group with the native disabled attribute.

<div role="radiogroup" class="radio-group" aria-label="Delivery speed">
  <label class="radio-option">
    <input kuiRadio type="radio" name="delivery" value="standard" checked />
    <span>Standard</span>
  </label>
  <label class="radio-option">
    <input kuiRadio type="radio" name="delivery" value="express" />
    <span>Express</span>
  </label>
  <label class="radio-option radio-option--disabled">
    <input kuiRadio type="radio" name="delivery" value="same-day" disabled />
    <span>Same day (unavailable in this region)</span>
  </label>
</div>

Inside kui-field, setting error text marks projected radio inputs invalid automatically. Use the invalid input directly only when a radio is used outside a field.

<kui-field label="Payment method" error="Select a payment method to continue" required>
  <div role="radiogroup" class="radio-group" aria-label="Payment method">
    <label class="radio-option">
      <input kuiRadio type="radio" name="payment" value="card" />
      <span>Card</span>
    </label>
    <label class="radio-option">
      <input kuiRadio type="radio" name="payment" value="bank-transfer" />
      <span>Bank transfer</span>
    </label>
  </div>
</kui-field>

Bind each native radio input with [formField] on an Angular Signal Forms field.

html.html
<kui-field label="Plan" hint="Choose a billing plan">
  <label>
    <input kuiRadio type="radio" name="plan" value="pro" [formField]="billingForm.plan" />
    Pro
  </label>
</kui-field>

Set defaults.radio once for the application or for a subtree. Each option resolves as local input > defaults.radio.<option> > built-in default.

import { provideKikitaUi } from '@kikita-labs/ui';

export const appConfig: ApplicationConfig = {
  providers: [
    provideKikitaUi({
      defaults: {
        radio: {
          /* options below */
        },
      },
    }),
  ],
};
NameTypeDefaultDescription
size'xs' | 'sm' | 'md' | 'lg' — Component size. Takes precedence over the global defaults.size.

Inputs verified against @kikita-labs/ui v2.0.0 public typings.

NameTypeDefaultDescription
size'xs' | 'sm' | 'md' | 'lg' | undefinedundefinedRadio size mapped to Kikita radio tokens. Resolved from defaults.radio.size, then the parent field, then the global defaults.size, then md.
invalidbooleanfalseMarks the radio invalid outside a kui-field error state. With [formField] the Field state wins.
idstring | undefinedundefinedExplicit id override. Inside kui-field, the field id is used when omitted.
KuiRadioOptionsinterface-Shape of defaults.radio: size.

Radio keeps native input semantics and adds field-described state when used inside kui-field.

  • Use a native label for each radio option's text.
  • Share a native name across radio inputs in the same group so keyboard arrow navigation and mutual exclusion work without extra scripting.
  • Wrap the group in a role="radiogroup" element with an accessible name (an aria-label or a kui-field label) so assistive technology announces the set.
  • Use kui-field for group label, hint, error, and described-by wiring.
  • Use native checked and disabled states; do not replace the input with a custom role.
  • Use invalid only when the radio is outside a field error state.
  • A required kui-field exposes aria-required on the radio inputs, and a checked radio stays visible under forced-colors: active.

Consumer-visible changes of @kikita-labs/ui 2.0 for Radio.

  • The directive class is KuiRadio; the Directive suffix is gone.
  • The default size moved to provideKuiDefaults({ radio: { size } }); the input is now undefined until set.
  • A required kui-field sets aria-required on the radio inputs.
  • The checked radio is covered by the forced-colors stylesheet, and disabled radios use the shared --kui-opacity-disabled.