Input · Radio

Radio

Radio component allows the user to select one option from a relative small set.

When to use

  • Used to select a single state among multiple options.
  • The difference from Select is that all available options in Radio are visible by default, making it easier for users to choose in comparison, so there should not be too many options.

Demos

How to import

import { Radio, RadioGroup } from '@fibrous/semi-ui-solid';

Basic Usage

Code
import { Radio } from '@fibrous/semi-ui-solid';

export default function RadioDemo() {
    return (
        <Radio aria-label="单选示例" name="demo-radio">
            Radio
        </Radio>
    );
}

Extra Info

You can use extra to add extra information, which can be any JSX.

Code
import { Radio } from '@fibrous/semi-ui-solid';

export default function RadioDemo() {
    return (
        <Radio extra="Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统" aria-label="单选示例" name="demo-radio-extra">
            Semi Design
        </Radio>
    );
}

Disabled


Code
import { createSignal } from 'solid-js';
import { Button, Radio } from '@fibrous/semi-ui-solid';

export default function RadioDemo() {
    const [disabled, setDisabled] = createSignal(true);
    return (
        <div>
            <Radio defaultChecked={false} disabled={disabled()} aria-label="单选示例" name="demo-radio-disabled">
                Disabled
            </Radio>
            <br />
            <Radio defaultChecked disabled={disabled()} aria-label="单选示例" name="demo-radio-defaultChecked-disabled">
                Disabled
            </Radio>
            <div style={{ 'margin-top': '20px' }}>
                <Button type="primary" onClick={() => setDisabled(!disabled())}>
                    Toggle disabled
                </Button>
            </div>
        </div>
    );
}

Advanced Mode

You can set mode='advanced' to allow options be able to unchecked when clicked again.

Code
import { createSignal } from 'solid-js';
import { Radio, type RadioChangeEvent } from '@fibrous/semi-ui-solid';

export default function RadioDemo() {
    const [checked, setChecked] = createSignal(true);
    const toggle = (e: RadioChangeEvent) => {
        console.log('radio checked', e.target.checked);
        setChecked(e.target.checked);
    };
    return (
        <Radio checked={checked()} mode="advanced" onChange={toggle} aria-label="单选示例" name="demo-radio-advanced">
            允许取消选择
        </Radio>
    );
}

Mutually Exclusive Set

You can use RadioGroup to create a set of mutually exclusive options.

Code
import { createSignal } from 'solid-js';
import { Radio, RadioGroup, type RadioChangeEvent } from '@fibrous/semi-ui-solid';

export default function RadioDemo() {
    const [value, setValue] = createSignal(1);
    const onChange = (e: RadioChangeEvent) => {
        console.log('radio checked', e.target.value);
        setValue(e.target.value);
    };
    return (
        <RadioGroup onChange={onChange} value={value()} aria-label="单选组合示例" name="demo-radio-group">
            <Radio value={1}>A</Radio>
            <Radio value={2}>B</Radio>
            <Radio value={3}>C</Radio>
            <Radio value={4}>D</Radio>
        </RadioGroup>
    );
}

vertical arrangement

The radio elements in the group can be arranged horizontally or vertically by setting the direction property to the RadioGroup

Code
import { Radio, RadioGroup } from '@fibrous/semi-ui-solid';

export default function RadioDemo() {
    return (
        <RadioGroup direction="vertical" aria-label="单选组合示例" name="demo-radio-group-vertical">
            <Radio value={1}>A</Radio>
            <Radio value={2}>B</Radio>
            <Radio value={3}>C</Radio>
            <Radio value={4}>D</Radio>
        </RadioGroup>
    );
}

Button Style

You can use type='button' to set the button style type radio, and the button type radio supports three sizes.

It should be noted that the button type radio selector does not support auxiliary text (extra) and vertical arrangement (direction='vertical').

Code
import { For } from 'solid-js';
import { Radio, RadioGroup, Space } from '@fibrous/semi-ui-solid';

const sizes = ['small', 'middle', 'large'] as const;

export default function RadioDemo() {
    return (
        <Space vertical spacing="loose" align="start">
            <For each={sizes}>
                {(size) => (
                    <RadioGroup type="button" buttonSize={size} defaultValue={1} aria-label="单选组合示例" name={`demo-radio-${size}`}>
                        <Radio value={1}>即时推送</Radio>
                        <Radio value={2}>定时推送</Radio>
                        <Radio value={3}>动态推送</Radio>
                    </RadioGroup>
                )}
            </For>
        </Space>
    );
}

Card Style

You can set type='card' to RadioGroup to achieve card style with background.

Code
import { Radio, RadioGroup } from '@fibrous/semi-ui-solid';

const extra = 'Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统';

export default function RadioDemo() {
    return (
        <RadioGroup type="card" defaultValue={2} direction="vertical" aria-label="单选组合示例" name="demo-radio-group-card">
            <Radio value={1} disabled extra={extra} style={{ width: '280px' }}>
                单选框标题
            </Radio>
            <Radio value={2} extra={extra} style={{ width: '280px' }}>
                单选框标题
            </Radio>
            <Radio value={3} extra={extra} style={{ width: '280px' }}>
                单选框标题
            </Radio>
        </RadioGroup>
    );
}

Pure Card Style

You can set type='pureCard' to RadioGroup to achieve a pure card style with background and no radio.

Code
import { Radio, RadioGroup } from '@fibrous/semi-ui-solid';

const extra = 'Semi Design 是由抖音前端团队与 UED 团队共同设计开发并维护的设计系统';

export default function RadioDemo() {
    return (
        <RadioGroup type="pureCard" defaultValue={2} direction="vertical" aria-label="单选组合示例" name="demo-radio-group-pureCard">
            <Radio value={1} disabled extra={extra} style={{ width: '280px' }}>
                单选框标题
            </Radio>
            <Radio value={2} extra={extra} style={{ width: '280px' }}>
                单选框标题
            </Radio>
            <Radio value={3} extra={extra} style={{ width: '280px' }}>
                单选框标题
            </Radio>
        </RadioGroup>
    );
}

Options Configuration

You can pass an array of options to RadioGroup using options property to create a set.

Code
import { createSignal } from 'solid-js';
import { RadioGroup, Space, type RadioChangeEvent } from '@fibrous/semi-ui-solid';

const plainOptions = ['Guest', 'Developer', 'Maintainer'];
const options = [
    { label: 'Guest', value: 'Guest', extra: 'Semi Design', style: { width: '120px' } },
    { label: 'Developer', value: 'Developer', extra: 'Semi Design', style: { width: '120px' } },
    { label: 'Maintainer', value: 'Maintainer', extra: 'Semi Design', style: { width: '120px' } },
];
const optionsWithDisabled = [
    { label: 'Guest', value: 'Guest' },
    { label: 'Developer', value: 'Developer' },
    { label: 'Maintainer', value: 'Maintainer', disabled: true },
];

export default function RadioDemo() {
    const [value1, setValue1] = createSignal('Guest');
    const [value2, setValue2] = createSignal('Developer');
    const [value3, setValue3] = createSignal('Maintainer');

    const onChange1 = (e: RadioChangeEvent) => {
        console.log('radio1 checked', e.target.value);
        setValue1(e.target.value);
    };
    const onChange2 = (e: RadioChangeEvent) => {
        console.log('radio2 checked', e.target.value);
        setValue2(e.target.value);
    };
    const onChange3 = (e: RadioChangeEvent) => {
        console.log('radio3 checked', e.target.value);
        setValue3(e.target.value);
    };

    return (
        <Space vertical align="start" spacing="loose">
            <RadioGroup options={plainOptions} onChange={onChange1} value={value1()} aria-label="单选组合示例" name="demo-radio-group-1" />
            <RadioGroup options={optionsWithDisabled} onChange={onChange2} value={value2()} aria-label="单选组合示例" name="demo-radio-group-2" />
            <RadioGroup options={options} onChange={onChange3} value={value3()} aria-label="单选组合示例" name="demo-radio-group-3" />
        </Space>
    );
}

API Reference

Radio

Props

PropertyDescriptionTypeDefault
addonClassNameClass name of the container wrapping the content.string-
addonIdId of the addon node, which aria-labelledby points to. Generated when omitted.string-
addonStyleInline style of the container wrapping the content.JSX.CSSProperties | string-
checkedWhether the radio is checked, for controlled use. Ignored inside a RadioGroup.boolean-
defaultCheckedWhether the radio is initially checked, for uncontrolled use. Ignored inside a RadioGroup.booleanfalse
disabledWhether the radio is disabled.boolean-
displayModeWhen set to vertical, the radio is displayed as a block and takes a line of its own.RadioDisplayMode-
extraSupplementary text, which aria-describedby points to. Not rendered when type is button.JSX.Element-
extraIdId of the extra node, which aria-describedby points to. Generated when omitted.string-
modeWhen set to advanced, a checked radio can be unchecked by clicking it or pressing Space. Inside a RadioGroup the group's mode applies.RadioMode""
nameThe native input's name. It takes precedence over the enclosing RadioGroup's name.string-
onBlurCalled when the native input loses focus.TypeJSX.EventHandlerUnion<HTMLInputElement, FocusEvent>-
onChangeCalled when the checked state changes. event.target is { checked, value, name, disabled }.Type(event: RadioChangeEvent) => void-
onFocusCalled when the native input receives focus.TypeJSX.EventHandlerUnion<HTMLInputElement, FocusEvent>-
prefixClsCSS class name prefix. When omitted it falls back to the enclosing RadioGroup's value, then the global default.string-
preventScrollWhether focusing prevents the browser from scrolling the element into view; applies to the focus method.boolean-
typeStyle type: default, button, card or pureCard. Inside a RadioGroup the group's type applies.RadioType"default"
valueThe radio's value, which a RadioGroup compares to decide whether it is checked. It is also the native input's value in form submission.string | number | boolean-

class, style and ref land on the root label element. id, name, tabindex, autofocus, aria-*, onFocus and onBlur land on the inner native input; other native attributes and events (such as onMouseEnter and onMouseLeave) land on the root element. extra is not rendered for the button type.

RadioGroup

Props

PropertyDescriptionTypeDefault
buttonSizeButton size when type is button: small, middle or large.RadioGroupButtonSize"middle"
defaultValueThe value selected by default when uncontrolled.string | number | boolean-
directionLayout direction of the radios: horizontal or vertical. Not supported when type is button.'horizontal' | 'vertical'"horizontal"
disabledWhether the whole group is disabled.booleanfalse
modeWhen set to advanced, a checked radio can be unchecked by clicking it or pressing Space.RadioMode""
nameThe name of every native input in the group. A unique value is generated per group when omitted.string-
onChangeCalled when the selected value changes. event.target is { checked, value, name, disabled }.Type(event: RadioChangeEvent) => void-
optionsDeclares the options as data. Each item is a string or { label, value, disabled, extra, class, style, addonId, addonStyle, addonClassName, extraId }, where label and extra hold only a string or number; other content goes through renderLabel and renderExtra. Children are ignored when set.Options-
prefixClsCSS class name prefix.string-
renderExtraRenders the extra text of an options item, given the item and its index. A button radio has no extra text and never calls it.Type(option: OptionItem, index: number) => JSX.Element-
renderLabelRenders the label of an options item, given the item and its index.Type(option: OptionItem, index: number) => JSX.Element-
typeStyle type of every Radio in the group: default, button, card or pureCard.RadioType"default"
valueThe selected value, for controlled use.string | number | boolean-

Each item in options has the fields label, value, disabled, extra (string | number), class, style, addonId, addonStyle, addonClassName and extraId, and no onChange. Use renderLabel(option, index) and renderExtra(option, index) for custom content; a button radio never calls renderExtra. class, style, ref, onBlur and native attributes land on the root element with role="radiogroup", and so do aria-required, aria-invalid and aria-errormessage; onBlur fires only when focus leaves the whole group. The aria-expanded, aria-haspopup, aria-controls and tabindex injected by Tooltip are not rendered.

Methods

Radio

ref receives the root label element; its focus() and blur() are forwarded to the inner native input, and preventScroll applies to focus().

Accessibility

ARIA

  • aria-label: used to explain the role of Radio or RadioGroup
  • aria-labelledby points to the addon node, used to explain the content of Radio
  • aria-describedby points to the extra node, which is used to explain the content of Radio
  • aria-required, aria-invalid and aria-errormessage apply to RadioGroup only and are set on the role="radiogroup" element. ARIA does not support them on a single Radio; when both aria-invalid and aria-errormessage are passed to it, the error message is linked to the input through aria-describedby

Keyboard and focus

WAI-ARIA: https://www.w3.org/WAI/ARIA/apg/patterns/radiobutton/

  • RadioGroup can be focused, the initial focus acquisition rules are as follows:
    • When there is no selected item in the RadioGroup, the initial focus is on the first Radio item;
    • When there are selected items in the RadioGroup, the initial focus is on the selected Radio item.
  • For radios belonging to the same radiogroup:
    • You can use Right arrow or Down arrow to move the focus to the next Radio item, uncheck the previously focused Radio item, and select the currently focused Radio item;
    • You can Use Left Arrow or Up Arrow to move the focus to the previous Radio item, at the same time uncheck the previously focused Radio item, and select the currently focused Radio item.
  • If there is no item selected in the RadioGroup, you can use the Space key to select the initial focus.
  • mode="advanced" is still a radio: arrow keys move the selection as usual, and clicking the selected item or pressing Space on it unchecks it.

Content Guidelines

  • Capitalize the first letter
  • No punctuation

Design Tokens

These are the component's internal Sass variables and cannot be overridden. To customize styles, override the --semi-* CSS variables (see the Design Token page) or write unlayered CSS rules.
Sass variableValueUsage
$transition_duration-radio-bgvar(--semi-transition_duration-none)单选框-背景色-动画持续时间
$transition_function-radio-bgvar(--semi-transition_function-easeIn)单选框-背景色-过渡曲线
$transition_delay-radio-bgvar(--semi-transition_delay-none)单选框-背景色-延迟时间
$transition_duration-radio-bordervar(--semi-transition_duration-none)单选框-边框-动画持续时间
$transition_function-radio-bordervar(--semi-transition_function-easeIn)单选框-边框-过渡曲线
$transition_delay-radio-bordervar(--semi-transition_delay-none)单选框-边框-延迟时间
$color-radio_default-border-defaultvar(--semi-color-text-3)单选圆圈描边颜色 - 默认态
$color-radio_default-bg-defaulttransparent单选圆圈背景颜色 - 默认态
$color-radio_default-bg-hovervar(--semi-color-fill-0)单选圆圈背景颜色 - 悬浮态
$color-radio_default-bg-activevar(--semi-color-fill-1)单选圆圈背景颜色 - 按下态
$color-radio_default-border-hovervar(--semi-color-focus-border)单选圆圈描边颜色 - 悬浮态
$color-radio_checked-border-hovervar(--semi-color-primary-hover)选中状态单选圆圈描边颜色 - 悬浮态
$color-radio_checked-border-activevar(--semi-color-primary-active)选中状态单选圆圈描边颜色 - 按下态
$color-radio_default-text-defaultvar(--semi-color-text-0)选项文本颜色
$color-radio_extra-text-defaultvar(--semi-color-text-2)辅助文本颜色
$color-radio_primary-bg-hovervar(--semi-color-primary-hover)选中状态单选圆圈背景颜色 - 悬浮态
$color-radio_primary-bg-activevar(--semi-color-primary-active)选中状态单选圆圈背景颜色 - 按下态
$color-radio_primary-border-defaultvar(--semi-color-primary)选中状态单选圆圈描边颜色 - 默认态
$color-radio_primary-bg-defaultvar(--semi-color-primary)选中状态单选圆圈背景颜色 - 默认态
$color-radio_primary-text-defaultvar(--semi-white)选中状态单选圆圈中心圆点颜色
$color-radio_checked-bg-disabledvar(--semi-color-primary-disabled)选中状态单选圆圈背景颜色 - 禁用态
$color-radio_default-border-disabledvar(--semi-color-border)单选圆圈描边颜色 - 禁用态
$color-radio_checked-border-disabledvar(--semi-color-primary-disabled)选中状态单选圆圈描边颜色 - 禁用态
$color-radio_disabled-bg-defaultvar(--semi-color-disabled-fill)单选圆圈背景颜色 - 禁用态
$color-radio_disabled-bg-hovertransparent
$color-radio_disabled-text-defaultvar(--semi-color-disabled-text)禁用态文本颜色
$color-radio_disabled-border-defaultvar(--semi-color-border)单选圆圈描边颜色 - 禁用态
$color-radio_checked-icon-disabledvar(--semi-white)选中且禁用状态下中心圆点颜色
$color-radio_buttonRadio-text-defaultvar(--semi-color-text-1)按钮样式单选文本颜色
$color-radio_buttonRadio-bg-defaultvar(--semi-color-fill-0)按钮样式单选背景颜色
$color-radio_buttonRadio-text-disabledvar(--semi-color-disabled-text)按钮样式单选禁用态文本颜色
$color-radio_addon_buttonRadio-bg-hovervar(--semi-color-fill-1)按钮样式单选悬浮态背景色
$color-radio_addon_buttonRadio-text-checkedvar(--semi-color-primary)按钮样式单选选中项文字颜色
$color-radio_addon_buttonRadio-bg-checkedvar(--semi-color-bg-3)按钮样式单选选中项背景颜色
$color-radio_cardRadioGroup-bg-defaulttransparent卡片样式单选默认背景色
$color-radio_cardRadioGroup-bg-checkedvar(--semi-color-primary-light-default)卡片样式单选选中态背景色
$color-radio_cardRadioGroup_disabled-bg-checkedvar(--semi-color-primary-light-default)卡片样式单选选中且禁用时的背景色
$color-radio_cardRadioGroup_disabled-bg-activetransparent卡片样式单选禁用时的背景色 - 按下态
$color-radio_cardRadioGroup-bg-hovervar(--semi-color-fill-0)卡片样式单选悬浮态背景色
$color-radio_cardRadioGroup-bg-activevar(--semi-color-fill-1)卡片样式单选按下态背景色
$color-radio_cardRadioGroup_border-defaulttransparent卡片样式单选默认描边颜色
$color-radio_cardRadioGroup_border-activevar(--semi-color-primary)卡片样式单选选中态描边颜色
$color-radio_cardRadioGroup_checked_border-activevar(--semi-color-primary-active)卡片样式单选选中态描边颜色 - 按下态
$color-radio_cardRadioGroup_checked_border-hovervar(--semi-color-primary-hover)卡片样式单选选中态描边颜色 - 悬浮态
$color-radio_cardRadioGroup_border_disabled-activevar(--semi-color-primary-disabled)卡片样式单选选中且禁用时的描边颜色
$color-radio_cardRadioGroup_addon-text-defaultvar(--semi-color-text-0)卡片样式单选标题文字颜色
$color-radio_cardRadioGroup_extra-text-defaultvar(--semi-color-text-2)卡片样式单选辅助文字颜色
$color-radio_cardRadioGroup_checked_disabled-border-defaultvar(--semi-color-primary-disabled)卡片样式选中项禁用态描边颜色 - 默认态
$color-radio_cardRadioGroup_checked_disabled-border-hovervar(--semi-color-primary-disabled)卡片样式选中项禁用态描边颜色 - 悬浮态
$color-radio_card-bg-hovervar(--semi-color-white)卡片模式下单选圆圈背景颜色 - 悬浮态
$color-radio_card-bg-activevar(--semi-color-white)卡片模式下单选圆圈背景颜色 - 按下态
$color-radio_card-bg-defaultvar(--semi-color-white)卡片模式下单选圆圈背景颜色 - 默认态
$color-radio_primary-outline-focus$color-focus-ring轮廓颜色 - 按键聚焦
$radius-radio_cardRadioGroupvar(--semi-border-radius-small)卡片式单选圆角大小
$radius-radio_addon_buttonRadiovar(--semi-border-radius-small)按钮式单选圆点圆角大小
$radius-radio_buttonRadiovar(--semi-border-radius-small)按钮式单选圆角大小
$width-radio_cardRadioGroup_checked-border1px卡片式单选描边宽度
$width-radio_cardRadioGroup_checked_disabled-border1px卡片式单选选中且禁用时的描边宽度
$width-radio_hover-border$border-thickness-control描边宽度 - 悬浮态
$width-radio_disabled-border$border-thickness-control描边宽度 - 禁用态
$width-radio_innder-border$border-thickness-control描边宽度 - 禁用态
$width-radio-outline$width-focus-ring单选框轮廓宽度
$height-radio_inner_min20px单选按钮高度
$width-radio_inner$width-icon-medium单选按钮宽度
$spacing-radio_addon-paddingLeft$spacing-tight单选标题到单选按钮左侧边距
$spacing-radio_addon_buttonRadio_large-paddingX$spacing-loose大尺寸按钮式单选按钮水平内边距
$spacing-radio_addon_buttonRadio_large-paddingY$spacing-base-tight * 0.5大尺寸按钮式单选按钮垂直内边距
$spacing-radio_addon_buttonRadio_small-paddingX$spacing-base小尺寸按钮式单选按钮水平内边距
$spacing-radio_addon_buttonRadio_small-paddingY$spacing-super-tight中尺寸按钮式单选按钮垂直内边距
$spacing-radio_addon_buttonRadio_middle-paddingX$spacing-base中尺寸按钮式单选按钮水平内边距
$spacing-radio_addon_buttonRadio_middle-paddingY$spacing-extra-tight中尺寸按钮式单选按钮垂直内边距
$spacing-radio_content-rowGap4px内容行间距
$spacing-radio_group_vertical-marginBottom$spacing-base-tight垂直布局单选框组底部外边距
$spacing-radio_group_horizontal-marginRight$spacing-base水平单选框组右侧外边距
$spacing-radio_buttonRadio-padding$spacing-extra-tight按钮式单选内边距
$spacing-radio_buttonRadioGroup_small-paddingX$spacing-super-tight小尺寸按钮式单选组水平内边距
$spacing-radio_buttonRadioGroup_small-paddingY$spacing-extra-tight小尺寸按钮式单选组垂直内边距
$spacing-radio_buttonRadioGroup_middle-padding$spacing-extra-tight中尺寸按钮式单选组内边距
$spacing-radio_buttonRadioGroup_large-padding$spacing-extra-tight大尺寸按钮式单选组内边距
$spacing-radio_buttonRadioGroup-paddingRight$spacing-none中尺寸按钮式单选组右侧内边距
$spacing-radio_cardRadioGroup-paddingX$spacing-base卡片式单选组水平内边距
$spacing-radio_cardRadioGroup-paddingY$spacing-base-tight卡片式单选组垂直内边距
$font-radio_buttonRadio_large-default-size$font-size-regular大尺寸按钮式单选标题字体大小
$font-radio_buttonRadio_small-default-size$font-size-small中尺寸按钮式单选标题字体大小
$font-radio_buttonRadio_middle-default-size$font-size-small小尺寸按钮式单选标题字体大小
$font-radio_buttonRadio-default-fontWeight$font-weight-bold按钮式单选标题字重 - 默认态
$font-radio_buttonRadio-hover-fontWeight$font-weight-bold按钮式单选标题字重 - 悬浮态
$font-radio_buttonRadio-checked-fontWeight$font-weight-bold按钮式单选标题字重 - 选中态
$font-radio_buttonRadioGroup_small-lineHeight16px小尺寸按钮式单选标题行高
$font-radio_buttonRadioGroup_middle-lineHeight16px中尺寸按钮式单选标题行高
$font-radio_buttonRadioGroup_large-lineHeight20px大尺寸按钮式单选标题行高
$font-radio_cardRadioGroup_addon-size$font-size-regular卡片式单选组标题字体大小
$font-radio_cardRadioGroup_addon-fontWeight$font-weight-bold卡片式单选组标题字体大小
$font-radio_cardRadioGroup_addon-lineHeight20px卡片式单选组标题行高
$font-radio_cardRadioGroup_extra-size$font-size-regular卡片式单选组副标题字体大小
$font-radio_cardRadioGroup_extra-fontWeightnormal卡片式单选组副标题字重
$font-radio_cardRadioGroup_extra-lineHeight20px卡片式单选组副标题行高