Radio Button
Radio Button Group allows the user to select exactly one value from a list of related but mutually exclusive options.
new tab
RadioButtonGroup<String> radioGroup = new RadioButtonGroup<>();
radioGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
radioGroup.setLabel("Travel class");
radioGroup.setItems("Economy", "Business", "First Class");
add(radioGroup);
States
Read-Only
Use read-only when content needs to be accessible but not editable. Read-only elements cannot be edited, but they do participate in the tabbing order and can thus receive focus. The contents of a read-only input can be selected and copied.
new tab
RadioButtonGroup<String> radioGroup = new RadioButtonGroup<>();
radioGroup.setLabel("Status");
radioGroup.setItems("In progress", "Done", "Cancelled");
radioGroup.setValue("In progress");
radioGroup.setReadOnly(true);
add(radioGroup);
Disabled
Disable a field to mark it as currently unavailable. Disabled state is used for fields that are not editable and do not need to be readable. Disabled elements cannot be focused and may be inaccessible to assistive technologies like screen readers.
Disabling can be preferable to hiding an element to prevent changes in layout when the element’s visibility changes, and to make users aware of its existence even when currently unavailable.
new tab
RadioButtonGroup<String> radioGroup = new RadioButtonGroup<>();
radioGroup.setLabel("Status");
radioGroup.setItems("In progress", "Done", "Cancelled");
radioGroup.setValue("In progress");
radioGroup.setEnabled(false);
add(radioGroup);
Orientation
The component’s default orientation is horizontal but vertical orientation is recommended whenever possible as it’s easier for the user to scan a vertical list of options:
new tab
RadioButtonGroup<String> radioGroup = new RadioButtonGroup<>();
radioGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
radioGroup.setLabel("Status");
radioGroup.setItems("Pending", "Submitted", "Confirmed");
radioGroup.setValue("Pending");
add(radioGroup);
In cases where vertical space needs to be conserved, horizontal orientation can be used, but no more than 3 options are recommended:
new tab
RadioButtonGroup<String> radioGroup = new RadioButtonGroup<>();
radioGroup.setLabel("Status");
radioGroup.setItems("Pending", "Submitted", "Confirmed");
radioGroup.setValue("Pending");
add(radioGroup);
In cases where more options need to be provided, the Select component can be used instead.
Custom Item Presentation
Items can be customised to include more than a single line of text:
new tab
RadioButtonGroup<Card> radioGroup = new RadioButtonGroup<>();
radioGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
radioGroup.setLabel("Payment method");
List<Card> cards = DataService.getCards();
radioGroup.setItems(cards);
radioGroup.setValue(cards.get(0));
radioGroup.setRenderer(new ComponentRenderer<>(card -> {
Image logo = new Image(card.getPictureUrl(), card.getName());
logo.setHeight("1em");
Span number = new Span(new Text(card.getAccountNumber()));
Text expiryDate = new Text("Expiry date:" + card.getExpiryDate());
return new Div(new HorizontalLayout(logo, number), new Div(expiryDate));
}));
add(radioGroup);
Best Practices
Group Labels
It is important to provide labels for Radio Button Groups to clearly distinguish them from one another, especially with multiple adjacent groups.
new tab
RadioButtonGroup<String> jobTitleGroup = new RadioButtonGroup<>();
jobTitleGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
jobTitleGroup.setLabel("Job title");
jobTitleGroup.setItems("Analyst", "Administrator", "Engineer");
jobTitleGroup.setValue("Analyst");
add(jobTitleGroup);
RadioButtonGroup<String> deparmentGroup = new RadioButtonGroup<>();
deparmentGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
deparmentGroup.setLabel("Department");
deparmentGroup.setItems("Engineering", "Human Resources", "Marketing");
deparmentGroup.setValue("Engineering");
add(deparmentGroup);
Custom Option
To enable the user to enter a custom option instead of picking one from the list, use an “Other” radio button at the bottom of the list with an associated Text Field for entry. The field should be hidden or disabled until the “Other” option is selected.
new tab
RadioButtonGroup<Card> radioGroup = new RadioButtonGroup<>();
radioGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
radioGroup.setLabel("Payment method");
List<Card> cards = new ArrayList<>(DataService.getCards());
Card other = new Card();
other.setId(-1);
cards.add(other);
radioGroup.setItems(cards);
radioGroup.setValue(cards.get(0));
radioGroup.setRenderer(new ComponentRenderer<>(card -> {
if (other.equals(card)) {
return new Text("Other");
} else {
Image logo = new Image(card.getPictureUrl(), card.getName());
logo.setHeight("1em");
Span number = new Span(new Text(card.getAccountNumber()));
return new HorizontalLayout(logo, number);
}
}));
TextField textField = new TextField("Card number");
textField.setVisible(false);
radioGroup.addValueChangeListener(e -> textField.setVisible(other.equals(e.getValue())));
add(radioGroup, textField);
Default Value and Blank Option
It is generally recommended to set the most common option as the default value for Radio Button Groups. Place the default option at the top of the list.
In cases where it is important that the user makes a conscious choice, the Radio Button Group should be blank by default.
In situations where the user isn’t required to select a value, use a “blank” option:
new tab
import { html, LitElement, customElement } from 'lit-element';
import '@vaadin/vaadin-radio-button/vaadin-radio-group';
import '@vaadin/vaadin-radio-button/vaadin-radio-button';
import { applyTheme } from 'Frontend/generated/theme';
@customElement('radio-button-default-value')
export class Example extends LitElement {
protected createRenderRoot() {
const root = super.createRenderRoot();
// Apply custom theme (only supported if your app uses one)
applyTheme(root);
return root;
}
render() {
return html`
<vaadin-radio-group label="Repeat" theme="vertical">
<vaadin-radio-button value="none" checked>None</vaadin-radio-button>
<vaadin-radio-button value="daily">Daily</vaadin-radio-button>
<vaadin-radio-button value="weekly">Weekly</vaadin-radio-button>
<vaadin-radio-button value="monthly">Monthly</vaadin-radio-button>
</vaadin-radio-group>
`;
}
}
As Alternative to a Checkbox
Two Radio Buttons can sometimes be a better alternative to a single Checkbox.
If the Checkbox does not represent a simple yes/no choice, and its label cannot clearly communicate the meaning of its unchecked state, it is better to use a Radio Button Group with two options:
new tab
import { html, LitElement, customElement } from 'lit-element';
import '@vaadin/vaadin-radio-button/vaadin-radio-group';
import '@vaadin/vaadin-radio-button/vaadin-radio-button';
import '@vaadin/vaadin-checkbox/vaadin-checkbox';
import '@vaadin/vaadin-ordered-layout/vaadin-vertical-layout';
import { applyTheme } from 'Frontend/generated/theme';
@customElement('radio-button-checkbox-alternative')
export class Example extends LitElement {
protected createRenderRoot() {
const root = super.createRenderRoot();
// Apply custom theme (only supported if your app uses one)
applyTheme(root);
return root;
}
render() {
return html`
<vaadin-vertical-layout>
<vaadin-checkbox checked>Reply All by default (unchecked state not clear)</vaadin-checkbox>
<vaadin-radio-group label="Default reply behavior">
<vaadin-radio-button checked>Reply</vaadin-radio-button>
<vaadin-radio-button>Reply to all</vaadin-radio-button>
</vaadin-radio-group>
</vaadin-vertical-layout>
`;
}
}
In a Horizontal Layout, Radio Button Groups also align more easily with other input fields than a single checkbox.
Related Components
Component | Usage recommendations |
---|---|
A dropdown field for selecting an item from a list of options. Recommended when there is insufficient space for a Radio Button Group. | |
A filterable, lazy loading alternative to Select, recommended for ten or more items. | |
Scrollable list of options. Supports single and multi-select. | |
Corresponding component for multi-select options. |
F93D1439-482C-4767-9E51-D0A1E61B9EC6