Pantrix UI

Radio Group

A group of radio buttons: a choice of one among options, under a label, with help or an error's message below.

import com.pantrixui.components.elements.radiobutton.PantrixRadioGroup

Examples

A group and its options

PantrixRadioGroup lays the options out one under another below label, and writes supportingText at the very bottom. Each option is a RadioOption; here what each one means is written under it. "Store pickup" cannot be selected (enabled = false): a press on it does nothing and the arrow keys skip it.

Try it with the keyboard: Tab enters the group once and stops on the selected option. The down and up arrows move the selection and the focus together, and wrap around from the last option to the first.

var delivery by rememberSaveable { mutableStateOf("standard") }
PantrixRadioGroup(
    options = DELIVERIES,
    selected = delivery,
    onSelect = { delivery = it },
    label = "Delivery",
    supportingText = "You can change it until the order ships",
    tagKey = "delivery"
)

private val DELIVERIES = listOf(
    RadioOption("standard", "Standard", supportingText = "Three to five working days", tagKey = "standard"),
    RadioOption("express", "Express", supportingText = "Next working day", tagKey = "express"),
    RadioOption(
        value = "pickup",
        label = "Store pickup",
        supportingText = "Not available in your city yet",
        enabled = false,
        tagKey = "pickup"
    )
)

Side by side

orientation = Orientation.Horizontal lays the options out side by side: as many on a line as the width takes, and the rest on the next line. The rings are aligned on the first line of their labels, whether or not something is written under a label.

The left and right arrows move the selection too; in a right-to-left layout they swap directions. The down and up arrows are the next and the previous option in both orientations.

var digest by rememberSaveable { mutableStateOf("weekly") }
PantrixRadioGroup(
    options = listOf(
        RadioOption("daily", "Every day", tagKey = "daily"),
        RadioOption("weekly", "Once a week", tagKey = "weekly"),
        RadioOption("monthly", "Once a month", tagKey = "monthly"),
        RadioOption("never", "Never", tagKey = "never")
    ),
    selected = digest,
    onSelect = { digest = it },
    orientation = Orientation.Horizontal,
    label = "Digest email",
    tagKey = "digest"
)

A choice of size bound to a form

The PantrixRadioGroup that takes a field is bound to a form's field: it gets its selection, its error and its name from the field. This is how a choice that has to be made is built: the field starts at null and carries Rules.required. The field's id is the automation key: the group is RadioGroup_size, and its options are named inside it.

Press "Add to cart" without picking a size: the rule's message takes the place of the supporting text, the rings turn to the error colour and the focus goes to the group. The sizes are laid out side by side; "XL" is sold out and cannot be selected.

val snackbars = LocalPantrixSnackbars.current
val scope = rememberCoroutineScope()
val form = rememberFormState()
PantrixRadioGroup(
    field = form.field<String?>("size", initial = null, Rules.required("Choose a size to continue")),
    options = SIZES,
    orientation = Orientation.Horizontal,
    label = "Size",
    supportingText = "Runs small; if you are between sizes, choose the larger one"
)
PantrixButton(
    text = "Add to cart",
    onClick = {
        scope.launch { form.submit { snackbars?.show(message = "Added to cart", tagKey = "added_to_cart") } }
    },
    form = form,
    tagKey = "add_to_cart"
)

private val SIZES = listOf("XS", "S", "M", "L", "XL", "XXL").map { size ->
    RadioOption(value = size.lowercase(), label = size, enabled = size != "XL", tagKey = size.lowercase())
}

Error

error turns the rings and the text under the group to the theme's danger role; the group tells a screen reader that the input is invalid, once. The texts under the options keep their colour: they say what an option is, not what is wrong.

Here the example works out the error itself: error is true while none is selected. Pick one: the rings and the text below go back to how they were.

var invoice by rememberSaveable { mutableStateOf<String?>(null) }
PantrixRadioGroup(
    options = listOf(
        RadioOption("personal", "Personal", supportingText = "The invoice is issued in your name", tagKey = "personal"),
        RadioOption("company", "Company", supportingText = "A tax number is required", tagKey = "company")
    ),
    selected = invoice,
    onSelect = { invoice = it },
    label = "Invoice type",
    supportingText = if (invoice == null) "Choose a type to continue" else "You can change it later",
    error = invoice == null,
    tagKey = "invoice"
)

Disabled and read-only

The group's enabled = false disables every option; the label and the supporting text are written in the disabled text colour too. Which option is selected can still be seen.

A PantrixRadioButton given onClick = null is read-only: it takes no press and no focus, its colours do not change, and it still says its name and that it is selected.

PantrixRadioGroup(
    options = listOf(
        RadioOption("card", "Card", tagKey = "card"),
        RadioOption("transfer", "Bank transfer", tagKey = "transfer")
    ),
    selected = "card",
    onSelect = {},
    orientation = Orientation.Horizontal,
    enabled = false,
    label = "Payment",
    supportingText = "Disabled: your saved card will be charged",
    tagKey = "payment"
)
PantrixRadioButton(
    selected = true,
    onClick = null,
    label = "Read-only",
    supportingText = "Cannot be pressed; it only shows what was chosen",
    tagKey = "read_only"
)

Its own colours

colors paints every option of the group. Here only the selected ring's colour was given (RadioColors(selected = …)): the selected ring and its dot are in the app's own purple, and the others stay in the theme's colour.

These are the colours of a ring that can be selected and is not in error. A disabled option and a group in error are drawn in the theme's colours, even when colours are given.

var wrapping by rememberSaveable { mutableStateOf("gift") }
PantrixRadioGroup(
    options = listOf(
        RadioOption("plain", "Plain", tagKey = "plain"),
        RadioOption("gift", "Gift wrap", tagKey = "gift")
    ),
    selected = wrapping,
    onSelect = { wrapping = it },
    orientation = Orientation.Horizontal,
    label = "Wrapping",
    supportingText = "The selected ring's colour was passed in; the others are in the theme's colour",
    colors = RadioColors(selected = ownColors().color),
    tagKey = "wrapping"
)

Style

style changes the ring of every option of the group: size is the size of the ring, dotSize that of the dot in it, and strokeWidth how thick the ring's line is. Only the fields that are given change; the rest comes from the theme's and the platform's style.

The ring here is 28dp, its dot 14dp and its line 3dp. The ring's colour is not part of the style: it comes from the state and from colors.

var seat by rememberSaveable { mutableStateOf("window") }
PantrixRadioGroup(
    options = listOf(
        RadioOption("window", "Window", tagKey = "window"),
        RadioOption("aisle", "Aisle", tagKey = "aisle")
    ),
    selected = seat,
    onSelect = { seat = it },
    orientation = Orientation.Horizontal,
    label = "Seat",
    style = RadioStyle(size = 28.dp, dotSize = 14.dp, strokeWidth = 3.dp),
    tagKey = "seat"
)

The rings at the end

The rings at the end of the options (controlPosition = ControlPosition.End): options one under another take the group's width, and their rings stand in a column at the group's end.

var delivery by rememberSaveable { mutableStateOf("standard") }
PantrixRadioGroup(
    options = DELIVERIES,
    selected = delivery,
    onSelect = { delivery = it },
    modifier = Modifier.widthIn(max = 360.dp),
    label = "Delivery",
    tagKey = "delivery_end",
    controlPosition = ControlPosition.End
)

private val DELIVERIES = listOf(
    RadioOption("standard", "Standard", supportingText = "Three to five working days", tagKey = "standard"),
    RadioOption("express", "Express", supportingText = "Next working day", tagKey = "express"),
    RadioOption(
        value = "pickup",
        label = "Store pickup",
        supportingText = "Not available in your city yet",
        enabled = false,
        tagKey = "pickup"
    )
)

API

options

A group of radio buttons: a choice of one among options, under a label, with help or an error's message below.

ParameterTypeDefaultWhat it is
optionsList<RadioOption<T>>the options, in order.
selectedT?the value of the selected option. Null, or a value no option has, selects none.
onSelect(T) -> Unitcalled with the value of the option the user chose, by a press or by the keys. The group selects nothing by itself: an option is selected when selected says so. A press on the option that is selected asks again, and an arrow key only ever asks for another option.
modifierModifierModifierthe group's modifier.
orientationOrientationOrientation.VerticalOrientation.Vertical for one option under another, Orientation.Horizontal for side by side.
enabledBooleantruefalse disables every option, and writes the label and the supporting text in the disabled text colour.
labelString?nullwhat the choice is, written over the options: the group's name for a screen reader.
supportingTextString?nullhelp under the options, in a smaller type: the message, while error is true.
errorBooleanfalsewhether the choice is wrong or missing: the rings and the supporting text turn to the danger role, and a screen reader is told the input is invalid.
styleRadioStyle?nullthis call's own style, the one every option is drawn with: over every enclosing one and under the density. Only the fields it sets change, on every platform.
colorsRadioColors?nullthe colours every option is drawn in, where they are not the theme's: the ones set here, with the theme's for the rest. A disabled option and a group in error keep the theme's.
tagKeyString?nullthe group's automation key: the group is RadioGroup_<tagKey>, and its options are named inside it, RadioGroup_<tagKey>.RadioButton_<key>, so that two groups with the same options are told apart. A choice is reported once, as a RadioGroup event that carries the option's index, and never its value or its label.
controlPositionControlPositionControlPosition.Startwhere each option's ring stands: before its label, or after it. After it, one under another, every option spans the group and the rings line up at its end; side by side, each ring follows its label.

field

A radio group bound to a form's field: its selection, its error and its name come from field.

ParameterTypeDefaultWhat it is
fieldFormField<T>the field the group shows and changes.
optionsList<RadioOption<T>>the options, in order.
modifierModifierModifierthe group's modifier.
orientationOrientationOrientation.VerticalOrientation.Vertical for one option under another, Orientation.Horizontal for side by side.
enabledBooleantruefalse disables every option.
labelString?nullwhat the choice is, written over the options: the group's name for a screen reader.
supportingTextString?nullhelp under the options, while the field has no error to show there.
styleRadioStyle?nullthis call's own style, the one every option is drawn with: over every enclosing one and under the density. Only the fields it sets change, on every platform.
colorsRadioColors?nullthe colours every option is drawn in, where they are not the theme's: the ones set here, with the theme's for the rest. A disabled option and a group in error keep the theme's.
controlPositionControlPositionControlPosition.Startwhere each option's ring stands: before its label, or after it. After it, one under another, every option spans the group and the rings line up at its end; side by side, each ring follows its label.

RadioStyle

PantrixRadioButton's ring and the dot in it: how large each is, and how thick the ring.

ParameterTypeDefaultWhat it is
sizeDpDp.UnspecifiedThe ring's width and height, its line included.
dotSizeDpDp.UnspecifiedThe width and height of the dot in a selected ring.
strokeWidthDpDp.UnspecifiedHow thick the ring's line is.

RadioColors

What PantrixRadioButton and the options of PantrixRadioGroup are painted with, for ones that do not take the theme's: a colour that is set is used, and one that is left out stays the theme's role.

ParameterTypeDefaultWhat it is
selectedColorColor.UnspecifiedThe ring and the dot of the option that is chosen. The theme's primary.
unselectedColorColor.UnspecifiedThe ring of an option that is not. The theme's borderStrong: an empty ring is nothing but its line.

Accessibility