RemixRemix
Actions and inputs

Radio

A radio button component for single-select options within a group

Open catalog
Starting Flutter example…
Live Flutter from this checkout’s component catalog. Examples include Fortal styling; the source tab shows the catalog code, not a standalone application.

A radio button component for selecting a single option from a group.

When to use this

  • Single selection: Allow users to choose one option from multiple choices
  • Form inputs: Collect single-choice preferences in forms
  • Settings: Enable users to select one configuration option
  • Surveys: Gather responses with mutually exclusive options

Basic implementation

Basic implementation

import 'package:flutter/material.dart';
import 'package:remix/remix.dart';

class RadioExample extends StatefulWidget {
  const RadioExample({super.key});

  @override
  State<RadioExample> createState() => _RadioExampleState();
}

class _RadioExampleState extends State<RadioExample> {
  String? _selectedValue;

  @override
  Widget build(BuildContext context) {
    return RemixRadioGroup<String>(
      groupValue: _selectedValue,
      onChanged: (value) {
        setState(() {
          _selectedValue = value;
        });
      },
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        spacing: 16,
        mainAxisSize: MainAxisSize.min,
        children: [
          Row(
            spacing: 8,
            mainAxisSize: MainAxisSize.min,
            children: [
              RemixRadio<String>(value: 'option1', semanticLabel: 'Option 1', style: style),
              const Text('Option 1'),
            ],
          ),
          Row(
            spacing: 8,
            mainAxisSize: MainAxisSize.min,
            children: [
              RemixRadio<String>(value: 'option2', semanticLabel: 'Option 2', style: style),
              const Text('Option 2'),
            ],
          ),
        ],
      ),
    );
  }

  RadioStyler get style {
    return RadioStyler()
        .borderRadius(.all(const Radius.circular(30)))
        .size(22, 22)
        .border(
          BoxBorderMix.all(
            BorderSideMix()
                .color(Colors.blueGrey.shade100)
                .width(2.4)
                .strokeAlign(BorderSide.strokeAlignInside),
          ),
        )
        .onHovered(
          RadioStyler().shadow(
            BoxShadowMix()
                .color(Colors.blueGrey.shade50.withValues(alpha: 0.7))
                .blurRadius(0)
                .spreadRadius(9),
          ),
        )
        .onPressed(
          RadioStyler().border(
            BoxBorderMix.all(
              BorderSideMix()
                  .color(Colors.blueGrey.shade100)
                  .width(6)
                  .strokeAlign(BorderSide.strokeAlignInside),
            ),
          ),
        )
        .onSelected(
          RadioStyler().border(
            BoxBorderMix.all(
              BorderSideMix()
                  .color(Colors.blueAccent.shade700)
                  .width(6)
                  .strokeAlign(BorderSide.strokeAlignInside),
            ),
          ),
        );
  }
}

Fortal widgets

The application-owned Fortal preset provides a themed widget for this component:

Fortal variants

import 'package:flutter/material.dart';
import 'package:remix/remix.dart';
import 'ui/ui.dart';

class FortalRadioExample extends StatefulWidget {
  const FortalRadioExample({super.key});

  @override
  State<FortalRadioExample> createState() => _FortalRadioExampleState();
}

class _FortalRadioExampleState extends State<FortalRadioExample> {
  String? _selected;

  @override
  Widget build(BuildContext context) {
    return RemixRadioGroup<String>(
      groupValue: _selected,
      onChanged: (value) => setState(() => _selected = value),
      child: Column(
        children: [
          Row(
            children: [
              FortalRadio.surface(
                value: 'surface',
                semanticLabel: 'Surface',
              ),
              const SizedBox(width: 8),
              const Text('Surface'),
            ],
          ),
          Row(
            children: [
              FortalRadio.soft(
                value: 'soft',
                semanticLabel: 'Soft',
              ),
              const SizedBox(width: 8),
              const Text('Soft'),
            ],
          ),
        ],
      ),
    );
  }
}

See the fortalRadioStyle source code for all available options.

Constructor

Constructor

import 'package:flutter/material.dart';
import 'package:remix/remix.dart';

// Radio Group
RemixRadioGroup<T> remixRadioGroupConstructor<T>({
  Key? key,
  required T? groupValue,
  ValueChanged<T?>? onChanged,
  required Widget child,
}) => throw UnimplementedError();

// Radio Button
RemixRadio<T> remixRadioConstructor<T>({
  Key? key,
  required T value,
  required String semanticLabel,
  bool enabled = true,
  bool toggleable = false,
  MouseCursor? mouseCursor,
  FocusNode? focusNode,
  bool autofocus = false,
  bool excludeSemantics = false,
  RadioStyler style = const RadioStyler.create(),
  RadioSpec? styleSpec,
}) => throw UnimplementedError();

Properties

Widget Properties

groupValue → T?

Required. The currently selected value for the radio group.

onChanged → ValueChanged<T?>?

Optional. Called when a radio button in the group is selected. When omitted, the radio group is disabled.

child → Widget

Required. The child widget that contains the radio buttons.

style → RadioStyler

Optional. The style configuration for the radio button. Customize colors, borders, and state-based styling.

styleSpec → RadioSpec?

Optional. A pre-resolved style spec that bypasses style resolution. Useful for performance when sharing resolved styles across multiple instances.

key → Key?

Optional. Controls how one widget replaces another widget in the tree.

value → T

Required. The value represented by this radio button.

autofocus → bool

Optional. Whether the radio button should automatically request focus when it is created.

enabled → bool

Optional. Whether this radio button is enabled.

toggleable → bool

Optional. Whether the radio button is toggleable (can be unselected).

focusNode → FocusNode?

Optional. The focus node for the radio button.

mouseCursor → MouseCursor?

Optional. The mouse cursor to use when hovering over the radio button.

semanticLabel → String

Required. The accessible name announced for this radio button. Must be nonblank — an adjacent Text label is not the accessible name.

excludeSemantics → bool

Optional. Whether to hide the radio button and its visual subtree from the semantics tree. Defaults to false.

indicator(BoxStyler value)

Sets indicator styling (selected fill).

alignment(Alignment value)

Sets container alignment.

padding(EdgeInsetsGeometryMix value)

Convenience for applying padding around the control.

margin(EdgeInsetsGeometryMix value)

Convenience for applying margin around the control.

size(double width, double height)

Sets container size using explicit constraints.

borderRadius(BorderRadiusGeometryMix radius)

Sets border radius on the outer container.

animate(AnimationConfig value)

Sets animation configuration.

wrap(WidgetModifierConfig value)

Applies widget modifiers such as clipping, opacity, or scaling.

constraints(BoxConstraintsMix value)

Sets size constraints on the component.

decoration(DecorationMix value)

Sets the container decoration.

foregroundDecoration(DecorationMix value)

Sets a foreground decoration painted on top of the component.

transform(Matrix4 value, AlignmentGeometry alignment = Alignment.center)

Applies a matrix transformation to the component.

call<T>({Key? key, required T value, required String semanticLabel, bool enabled = true, bool toggleable = false, MouseCursor? mouseCursor, FocusNode? focusNode, bool autofocus = false, bool excludeSemantics = false})

Creates a RemixRadio<T> widget with this style applied.

View page source on GitHub

On this page