ChoiceButton
ChoiceButton is a radio button wrapped in a card-like container. It's used in question/answer scenarios where it's useful to show additional information for each option.
Code example
import { ChoiceButton } from '@yleisradio/yds-components-react';
<ChoiceButton name="choice-1" label="Option 1" />
Why to use
ChoiceButton gives you a consistent, accessible way to present single-select options in a card layout. It extends Radio with an optional icon, extra content below the label, and right/wrong answer indicator — so you can highlight options or show results without building custom layouts.
When to use
Use ChoiceButton when options need a card-style container: each choice has an icon, a short description, or should stand out visually. Use plain Radio (and RadioGroup) when options are simple labels in a list.
- Use for question/answer patterns.
- Don't use as a regular form component. Use Radio instead.
Content guidelines
Keep labels short and parallel. Put longer explanations in the content prop or in a group description.
- Use the optional icon and status to tell the user if the answer is correct or incorrect.
- Use
contentfor brief supporting text, not for the main choice label.
- Don't use long sentences as the main label — move detail into
contentor description.
Key ChoiceButton Props
Use these props to configure the ChoiceButton component.
label
Label text or content for the radio button.
| Type | Example | Description |
|---|---|---|
React.ReactNode | Label content for the radio button |
Code example
<ChoiceButton name="option-group" label="Option 1" />
<ChoiceButton name="option-group" label={<strong>Bold Option</strong>} />
status
Visual status indicator for the choice button.
| Value | Example | Description |
|---|---|---|
success | Success status styling | |
error | Error status styling |
Code example
<ChoiceButton name="option-group" label="Option" status="success" />
<ChoiceButton name="option-group" label="Option" status="error" />
controlAlign
Alignment of the radio control relative to the content.
| Value | Example | Description |
|---|---|---|
start | Aligns control to the start | |
end | Aligns control to the end |
Code example
<ChoiceButton name="option-group" label="Option" controlAlign="start" />
<ChoiceButton name="option-group" label="Option" controlAlign="end" />
containerSize
Size of the choice container.
| Value | Example | Description |
|---|---|---|
sm | Small container size | |
md | Medium container size (default) |
Code example
<ChoiceButton name="option-group" label="Option" containerSize="sm" />
<ChoiceButton name="option-group" label="Option" containerSize="md" />
icon
Optional icon to display in the choice container.
| Type | Example | Description |
|---|---|---|
React.ReactNode | Icon element to display |
Code example
import { Check } from '@yleisradio/yds-icons-react';
<ChoiceButton name="option-group" label="Option" icon={<Check />} />
content
Additional content to display below the radio button and icon.
| Type | Example | Description |
|---|---|---|
React.ReactNode | Some additional content | Additional content below the control |
Code example
<ChoiceButton
name="option-group"
label="Option"
content={<p style={{ margin: 16 }}>Some additional content</p>}
/>
isDisabled
Whether the radio button is disabled.
| Type | Example | Description |
|---|---|---|
boolean | Disables the radio button |
Code example
<ChoiceButton name="option-group" label="Option" isDisabled />
variant
Visual style variant of the radio button.
| Value | Example | Description |
|---|---|---|
primary | Primary variant (default) | |
secondary | Secondary variant |
Code example
<ChoiceButton name="option-group" label="Option" variant="primary" />
<ChoiceButton name="option-group" label="Option" variant="secondary" />
useUnderlay
Whether to show an underlay effect.
| Type | Example | Description |
|---|---|---|
boolean | Shows underlay effect |
Code example
<ChoiceButton name="option-group" label="Option" useUnderlay />
Behavior
- All ChoiceButtons in a group share the same
name; only one can be selected at a time. - Selection is controlled via
checked/defaultCheckedandonChange, or via a parent like RadioGroup. - The container has an underlay by default (
useUnderlay={true}). status="success"orstatus="error"applies visual feedback.- Disabled options are non-interactive but remain visible.
Accessibility
- Every ChoiceButton must have a visible or programmatically associated label (use
labelorhideLabelwith meaningful accessible name).
(WCAG 3.3.2 — Labels or Instructions) - Group related options under a shared name and, when possible, a fieldset or group label so the relationship is clear.
(WCAG 1.3.1 — Info and Relationships) - Keyboard: Tab/Shift+Tab move focus between options; Arrow keys move between radio buttons in the same group; Space selects the focused option.
(WCAG 2.1.1 — Keyboard)
Implementation examples
Abitreenit example
Code example
import { useState } from 'react';
import { Check, Close } from '@yleisradio/yds-icons-react';
import { ChoiceButton as ChoiceButtonComponent } from '@yleisradio/yds-components-react';
export const ChoiceButton = () => {
const [choices, setChoices] = useState([
{
label: 'infrapunaspektroskopia',
correct: false,
icon: null,
status: null,
},
{
label: 'massaspektrometria',
correct: false,
icon: null,
status: null,
},
{
label: 'uuttaminen',
correct: true,
icon: null,
status: null,
},
{
label: 'sulamispisteen määritys',
correct: false,
icon: null,
status: null,
},
]);
const handleChoiceChange = (value: string) => {
setChoices((c) =>
c.map((choice) => {
if (choice.label === value) {
return {
...choice,
icon: choice.correct ? <Check /> : <Close />,
status: choice.correct ? 'success' : 'error',
};
}
if (choice.correct) {
return {
...choice,
icon: <Check />,
status: 'success',
};
}
return {
...choice,
icon: null,
status: null,
};
})
);
};
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
Mikä seuraavista tekniiko ista on kemiallinen erotusmenetelmä?
{choices.map((choice) => (
<ChoiceButtonComponent
name="choice-1"
label={choice.label}
icon={choice.icon}
onChange={() => handleChoiceChange(choice.label)}
status={choice.status}
/>
))}
</div>
);
};
API Reference
Props
The ChoiceButton component accepts all standard HTML <input> attributes (except size) in addition to the following props:
| Prop | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Name attribute for grouping radio buttons |
label | React.ReactNode | Yes | — | Label content for the radio button |
status | 'success' | 'error' | No | — | Visual status indicator |
controlAlign | 'start' | 'end' | No | — | Alignment of radio control |
containerSize | 'sm' | 'md' | No | — | Size of the choice container |
icon | React.ReactNode | No | — | Optional icon to display |
content | React.ReactNode | No | — | Additional content below control |
isDisabled | boolean | No | false | Whether the radio button is disabled |
variant | 'primary' | 'secondary' | No | 'primary' | Visual style variant |
value | string | No | — | Value attribute for form submission |
hideLabel | boolean | No | false | Visually hides the label |
useUnderlay | boolean | No | true | Shows underlay effect |
Type Definitions
export type ChoiceContainerStatus = 'success' | 'error';
export type InputControlAlign = 'start' | 'end';
export type ChoiceContainerSize = 'sm' | 'md';
export type ChoiceHTMLInputAttributes = Omit<InputHTMLAttributes<HTMLInputElement>, 'size'>;
export interface ChoiceButtonDSProps {
status?: ChoiceContainerStatus;
controlAlign?: InputControlAlign;
containerSize?: ChoiceContainerSize;
icon?: React.ReactNode;
content?: React.ReactNode;
}
export type RadioPropsNoError = Omit<RadioProps, 'error'>;
export type ChoiceButtonProps = ChoiceHTMLInputAttributes & ChoiceButtonDSProps & RadioPropsNoError;