Radio 单选按钮
@lark-ui/core
通知偏好
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示基础的受控单选按钮组(Radio) */
export function RadioBasicDemo() {
  const [value, setValue] = useState("email");
  return (
    <Radio.Group legend="通知偏好" value={value} onValueChange={setValue}>
      <Radio.Item label="邮件" value="email" />
      <Radio.Item label="短信" value="sms" />
      <Radio.Item label="推送通知" value="push" />
    </Radio.Group>
  );
}

安装

统一导出

import { Radio } from "@lark-ui/core";

按需导出

import { Radio } from "@lark-ui/core/components/radio";

用法

import { Radio } from "@lark-ui/core";

export default function Example() {
  return (
    <Radio.Group legend="Choose an option" defaultValue="a">
      <Radio.Item label="Option A" value="a" />
      <Radio.Item label="Option B" value="b" />
    </Radio.Group>
  );
}

示例

默认(垂直)

单选按钮组(Radio.Group)默认垂直排列。每个单选按钮的标签显示在其右侧。

账户类型
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示默认的纵向单选按钮组布局 */
export function RadioDefaultDemo() {
  const [value, setValue] = useState("personal");
  return (
    <Radio.Group legend="账户类型" value={value} onValueChange={setValue}>
      <Radio.Item label="个人" value="personal" />
      <Radio.Item label="商业" value="business" />
      <Radio.Item label="企业版" value="enterprise" />
    </Radio.Group>
  );
}

水平排列

使用 orientation="horizontal" 可获得行内布局。空间不足时选项会自动换行。

尺寸
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示横向单选按钮组布局 */
export function RadioHorizontalDemo() {
  const [value, setValue] = useState("md");
  return (
    <Radio.Group
      legend="尺寸"
      orientation="horizontal"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item label="小" value="sm" />
      <Radio.Item label="中" value="md" />
      <Radio.Item label="大" value="lg" />
    </Radio.Group>
  );
}

分段样式

使用 appearance="segmented" 可获得行内紧凑的选项。选项不会换行,因此请据此设计布局。

时长预设
import { useState } from "react";
import { Radio } from "@lark-ui/core";

export function RadioSegmentedDemo() {
  const [duration, setDuration] = useState("1");
  return (
    <Radio.Group
      appearance="segmented"
      legend="时长预设"
      value={duration}
      onValueChange={setDuration}
    >
      <Radio.Item label="1h" value="1" />
      <Radio.Item label="12h" value="12" />
      <Radio.Item label="24h" value="24" />
    </Radio.Group>
  );
}

是否应该使用分段样式?

仅当分组较小、标签简短且控件能放下一行时,才使用分段样式。标签较长、需要描述性选项、选项数量较多或布局较窄时,请使用默认样式。

当选择结果决定显示哪个内容面板时,请使用 标签页(Tabs) 组件。

默认与分段对比

外观仅影响呈现方式。两个示例表达的是同一组互斥的选项。

默认外观
分段外观
import { Radio } from "@lark-ui/core";

export function RadioAppearanceComparisonDemo() {
  return (
    <div className="flex flex-wrap gap-8">
      <Radio.Group legend="默认外观" orientation="horizontal" defaultValue="1">
        <Radio.Item label="1h" value="1" />
        <Radio.Item label="12h" value="12" />
        <Radio.Item label="24h" value="24" />
      </Radio.Group>
      <Radio.Group appearance="segmented" legend="分段外观" defaultValue="1">
        <Radio.Item label="1h" value="1" />
        <Radio.Item label="12h" value="12" />
        <Radio.Item label="24h" value="24" />
      </Radio.Group>
    </div>
  );
}

禁用的分段控件

分段控件组支持禁用整个分组或禁用单个选项。

禁用的单选组
禁用的选项
import { Radio } from "@lark-ui/core";

export function RadioSegmentedDisabledDemo() {
  return (
    <div className="flex flex-wrap gap-8">
      <Radio.Group
        appearance="segmented"
        legend="禁用的单选组"
        defaultValue="12"
        disabled
      >
        <Radio.Item label="1h" value="1" />
        <Radio.Item label="12h" value="12" />
        <Radio.Item label="24h" value="24" />
      </Radio.Group>
      <Radio.Group appearance="segmented" legend="禁用的选项" defaultValue="1">
        <Radio.Item label="1h" value="1" />
        <Radio.Item label="12h" value="12" disabled />
        <Radio.Item label="24h" value="24" />
      </Radio.Group>
    </div>
  );
}

使用自定义图例的分段控件

Radio.Legend 保持在分段控件表面之外,为分组提供无障碍名称。

配置模式
import { Radio } from "@lark-ui/core";

export function RadioSegmentedLegendDemo() {
  return (
    <Radio.Group appearance="segmented" defaultValue="automatic">
      <Radio.Legend className="text-sm font-normal text-lark-subtle">
        配置模式
      </Radio.Legend>
      <Radio.Item label="自动" value="automatic" />
      <Radio.Item label="手动" value="manual" />
    </Radio.Group>
  );
}

长标签与窄布局

分段控件保持其固有宽度,不会换行、收缩或截断选项。当翻译后的标签或过窄的容器导致分组 无法排在一行内时,请选择默认样式。

处理偏好
import { Radio } from "@lark-ui/core";

export function RadioSegmentedLongLabelsDemo() {
  return (
    <div className="w-48 max-w-full">
      <Radio.Group
        appearance="segmented"
        legend="处理偏好"
        defaultValue="automatic"
      >
        <Radio.Item label="自动处理" value="automatic" />
        <Radio.Item label="手动配置" value="manual" />
      </Radio.Group>
    </div>
  );
}

带描述

使用 description 属性可以在单选按钮下方添加辅助说明文字。

配送方式

选择你希望接收订单的方式

import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示带辅助说明文字的单选按钮组 */
export function RadioDescriptionDemo() {
  const [value, setValue] = useState("standard");
  return (
    <Radio.Group
      legend="配送方式"
      description="选择你希望接收订单的方式"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item label="标准(5-7 天)" value="standard" />
      <Radio.Item label="加急(2-3 天)" value="express" />
      <Radio.Item label="隔夜送达" value="overnight" />
    </Radio.Group>
  );
}

控件位置

使用 controlPosition="end" 可以把标签放在单选按钮之前。

偏好设置
import { Radio } from "@lark-ui/core";

/** 展示标签位于单选控件之前的单选按钮组 */
export function RadioControlPositionDemo() {
  return (
    <Radio.Group legend="偏好设置" controlPosition="end" defaultValue="a">
      <Radio.Item label="标签在单选按钮之前" value="a" />
      <Radio.Item label="另一个选项" value="b" />
    </Radio.Group>
  );
}

单选卡片

在分组上使用 appearance="card",可以把每个选项显示为同一张卡片中的可选行,行之间用 分隔线隔开。结合每个选项上的 description 属性可以呈现更丰富的内容。

选择套餐
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示带 Lark 套餐选项的单选卡片外观 */
export function RadioCardDemo() {
  const [value, setValue] = useState("free");
  return (
    <Radio.Group
      legend="选择套餐"
      appearance="card"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item
        label="免费版"
        description="适合个人或业余项目,不适合关键业务场景。"
        value="free"
      />
      <Radio.Item
        label="专业版"
        description="适合专业网站,不适合关键业务场景。"
        value="pro"
      />
      <Radio.Item
        label="商业版"
        description="适合线上运营的小型企业。"
        value="business"
      />
      <Radio.Item
        label="合约版"
        description="适合作为业务核心的关键应用。"
        value="contract"
      />
    </Radio.Group>
  );
}

单选卡片(控件在左侧)

在卡片式单选按钮组上使用 controlPosition="start",可以把单选控件放在标签和描述的左侧。

选择套餐
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示通过 controlPosition="start" 将控件置于左侧的单选卡片外观 */
export function RadioCardControlStartDemo() {
  const [value, setValue] = useState("free");
  return (
    <Radio.Group
      legend="选择套餐"
      appearance="card"
      controlPosition="start"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item
        label="免费版"
        description="适合个人或业余项目,不适合关键业务场景。"
        value="free"
      />
      <Radio.Item
        label="专业版"
        description="适合专业网站,不适合关键业务场景。"
        value="pro"
      />
    </Radio.Group>
  );
}

富标签内容

Radio.Item 上的 label 属性接受 React 节点,因此你可以在文本旁嵌入图标、徽标或其他标记。

选择套餐
import { useState } from "react";
import { Badge, Radio } from "@lark-ui/core";

/** 展示 Radio.Item 标签中使用富文本 ReactNode 内容(图标、徽标或额外标记) */
export function RadioRichLabelDemo() {
  const [value, setValue] = useState("pro");
  return (
    <Radio.Group
      legend="选择套餐"
      appearance="card"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item
        label={
          <span className="flex items-center gap-2">
            免费版
            <Badge variant="neutral">$0</Badge>
          </span>
        }
        description="适合个人或业余项目。"
        value="free"
      />
      <Radio.Item
        label={
          <span className="flex items-center gap-2">
            专业版
            <Badge variant="primary">热门</Badge>
          </span>
        }
        description="适合专业网站。"
        value="pro"
      />
    </Radio.Group>
  );
}

单选卡片(水平)

将 appearance="card" 与 orientation="horizontal" 结合使用,可以在同一张卡片内把选项 排成两列。

选择套餐
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示横向布局的单选卡片外观 */
export function RadioCardHorizontalDemo() {
  const [value, setValue] = useState("free");
  return (
    <Radio.Group
      legend="选择套餐"
      appearance="card"
      orientation="horizontal"
      value={value}
      onValueChange={setValue}
    >
      <Radio.Item
        label="免费版"
        description="适合个人或业余项目,不适合关键业务场景。"
        value="free"
      />
      <Radio.Item
        label="专业版"
        description="适合专业网站,不适合关键业务场景。"
        value="pro"
      />
      <Radio.Item
        label="商业版"
        description="适合线上运营的小型企业。"
        value="business"
      />
      <Radio.Item
        label="合约版"
        description="适合作为业务核心的关键应用。"
        value="contract"
      />
    </Radio.Group>
  );
}

带错误

使用 error 属性在分组级别展示校验错误。

支付方式

请选择一种支付方式以继续

支付方式

请选择一种支付方式以继续

import { Radio } from "@lark-ui/core";

/** 展示默认样式和卡片样式单选按钮组的错误状态 */
export function RadioErrorDemo() {
  return (
    <div className="grid grid-cols-2 gap-6">
      <Radio.Group legend="支付方式" error="请选择一种支付方式以继续">
        <Radio.Item label="信用卡" value="card" variant="error" />
        <Radio.Item label="PayPal" value="paypal" variant="error" />
      </Radio.Group>
      <Radio.Group
        legend="支付方式"
        appearance="card"
        error="请选择一种支付方式以继续"
      >
        <Radio.Item
          label="信用卡"
          description="可使用 Visa、Mastercard、美国运通或 Elo 支付。"
          value="card"
          variant="error"
        />
        <Radio.Item
          label="PayPal"
          description="使用你的 PayPal 账户支付。"
          value="paypal"
          variant="error"
        />
      </Radio.Group>
    </div>
  );
}

禁用

禁用整个分组或单个选项。

禁用的单选组
单独禁用
禁用的卡片单选组
单独禁用的卡片
import { Radio } from "@lark-ui/core";

/** 展示默认样式和卡片样式单选按钮组的禁用状态 */
export function RadioDisabledDemo() {
  return (
    <div className="grid grid-cols-2 gap-6">
      <Radio.Group legend="禁用的单选组" disabled defaultValue="a">
        <Radio.Item label="选项 A" value="a" />
        <Radio.Item label="选项 B" value="b" />
      </Radio.Group>
      <Radio.Group legend="单独禁用" defaultValue="available">
        <Radio.Item label="可用" value="available" />
        <Radio.Item label="不可用" value="unavailable" disabled />
      </Radio.Group>
      <Radio.Group
        legend="禁用的卡片单选组"
        appearance="card"
        disabled
        defaultValue="a"
      >
        <Radio.Item label="选项 A" description="该选项已禁用。" value="a" />
        <Radio.Item label="选项 B" description="该选项已禁用。" value="b" />
      </Radio.Group>
      <Radio.Group
        legend="单独禁用的卡片"
        appearance="card"
        defaultValue="available"
      >
        <Radio.Item
          label="可用"
          description="该选项可以选择。"
          value="available"
        />
        <Radio.Item
          label="不可用"
          description="该选项不可用。"
          value="unavailable"
          disabled
        />
      </Radio.Group>
    </div>
  );
}

视觉隐藏的图例

在 Radio.Legend 上使用 className="sr-only",可以让图例对屏幕阅读器保持可访问,同时在 视觉上隐藏。当单选按钮组已经由父级 Field 或标题标注,显示图例会造成标签重复时,这会 非常有用。

路径
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示使用 sr-only 的 Radio.Legend,在保留无障碍语义的同时视觉隐藏图例;当父级 Field 已提供可见标签时非常有用 */
export function RadioLegendSrOnlyDemo() {
  const [value, setValue] = useState("all");
  return (
    <Radio.Group defaultValue="all" value={value} onValueChange={setValue}>
      <Radio.Legend className="sr-only">路径</Radio.Legend>
      <Radio.Item label="允许所有路径" value="all" />
      <Radio.Item label="限制为特定路径" value="specific" />
    </Radio.Group>
  );
}

自定义图例样式

Radio.Legend 接受 className,可完全控制图例的呈现方式。当需要自定义排版、颜色或布局时, 请使用它代替 legend 字符串属性。

通知偏好
import { useState } from "react";
import { Radio } from "@lark-ui/core";

/** 展示使用自定义样式的 Radio.Legend,完全掌控图例的呈现方式 */
export function RadioLegendCustomDemo() {
  const [value, setValue] = useState("email");
  return (
    <Radio.Group value={value} onValueChange={setValue}>
      <Radio.Legend className="text-sm font-normal text-lark-subtle">
        通知偏好
      </Radio.Legend>
      <Radio.Item label="邮件" value="email" />
      <Radio.Item label="短信" value="sms" />
      <Radio.Item label="推送通知" value="push" />
    </Radio.Group>
  );
}

类型化取值

Radio.Group 和 Radio.Item 支持泛型。传入类型参数(例如 <number> 或枚举类型),可以 约束两个子组件上 value 的类型,以及 Radio.Group 上的 defaultValue 和 onValueChange。 省略时默认为 string。

每页条数
主题
enum ThemeType {
  dark = "dark",
  light = "light",
  system = "system",
}

export function RadioTypedValueDemo() {
  const [pageSize, setPageSize] = useState<number>(10);
  const [theme, setTheme] = useState<ThemeType>(ThemeType.system);
  return (
    <div className="grid grid-cols-2 gap-6">
      <Radio.Group<number>
        legend="Items per page"
        value={pageSize}
        onValueChange={setPageSize}
      >
        <Radio.Item<number> label="10" value={10} />
        <Radio.Item<number> label="25" value={25} />
        <Radio.Item<number> label="50" value={50} />
      </Radio.Group>
      <Radio.Group<ThemeType>
        legend="Theme"
        value={theme}
        onValueChange={setTheme}
      >
        <Radio.Item<ThemeType> label="Light" value={ThemeType.light} />
        <Radio.Item<ThemeType> label="Dark" value={ThemeType.dark} />
        <Radio.Item<ThemeType> label="System" value={ThemeType.system} />
      </Radio.Group>
    </div>
  );
}

API 参考

Radio.Group

单选按钮的容器,支持图例(legend)、描述和错误提示。

属性类型默认值说明
legendstring-分组标题文字(无障碍访问必需)。如需更多控制标题样式,请省略此属性,改用 `<Radio.Legend>` 作为子元素。
children*ReactNode-子级的 Radio.Item 组件(也可以包含 Radio.Legend)
orientation"vertical" | "horizontal"-单选项的排列方向
appearanceLarkRadioAppearance-应用到所有 Radio.Item 子元素的外观样式。- `"default"` — 标准行内单选项 - `"card"` — 带边框、内边距和高亮选中态的选项卡片 - `"segmented"` — 适合少量选项的单行紧凑分组 单个单选项可以覆盖默认和卡片外观;分段式仅用于分组,不能被单个单选项覆盖。
errorstring-分组的错误信息
descriptionReactNode-分组的辅助说明文字
valueT-选中单选项的受控值。
disabledboolean-分组内所有单选按钮是否禁用
controlPositionRadioControlPosition-单选控件相对标签的位置:“start”把单选按钮放在标签之前,“end”把标签放在单选按钮之前。默认外观下为“start”,卡片外观下为“end”。
namestring-单选分组在表单提交时使用的名称
classNamestring-额外的 CSS 类名
defaultValueT-选中单选项的初始值(非受控)。
onValueChange(value: T, eventDetails: RadioGroupChangeEventDetails) => void-选中值变化时触发的回调。第二个参数携带关于本次交互的原生事件信息。

Radio.Legend

Radio.Group 的可组合图例子组件。接受 className,可完全控制样式(例如用 className="sr-only" 在视觉上隐藏)。当需要自定义图例样式时,请使用它代替 legend 字符串属性。

属性类型默认值说明
children*ReactNode-标题内容
classNamestring-额外的 CSS 类名(例如用 “sr-only” 在视觉上隐藏标题)

Radio.Item

Radio.Group 中的单个单选按钮。

属性类型默认值

该组件没有专有属性,支持标准 HTML 属性。

无障碍

语义化 HTML

Radio.Group 使用语义化的 <fieldset> 和 <legend> 元素来实现正确的分组和屏幕阅读器播报。

键盘导航

使用 Arrow Up/Down 或 Arrow Left/Right 在选项之间移动。Space 选中当前聚焦的选项。Tab 将焦点移入或移出单选按钮组。

屏幕阅读器

每个单选按钮都会播报其标签和选中状态。分组图例为所有选项提供上下文。