AniBTUI
✦ 组件@anibt/radio-groupregistry JSON

Radio Group

18px 的糖果单选:选中的一项是糖果粉加白点,和勾选框同一种填充。

默认画质

安装

npx shadcn@latest add @anibt/radio-group

第一次用之前:在 components.json 里登记 @anibt,再单独运行一次 npx shadcn@latest add @anibt/theme(见快速开始)。只有单独安装主题时,CLI 才会把 shadcn 的标准颜色换成白樱 / 夜樱;随组件带进来的主题只补上 AniBT 自己的变量和配方。

手动安装
  1. 1. 先装主题组件只读 @anibt/theme 的 token 和配方,没有主题就没有样子。
    npx shadcn@latest add @anibt/theme
  2. 2. 安装依赖
    npm install radix-ui
  3. 3. 把下面的文件放进项目
    components/ui/radio-group.tsx
    "use client"
    
    import * as React from "react"
    import { RadioGroup as RadioGroupPrimitive } from "radix-ui"
    
    import { cn } from "@/lib/utils"
    
    /**
     * RadioGroup — A's candy radio (AniBT 「贴纸手账」).
     *
     * An 18px paper disc inside a 1.5px `--input` ring (pink under the pointer);
     * the chosen one is candy with a white dot that pops in, the same fill as a
     * ticked checkbox, so a column of options reads at a glance. Focus is the
     * 2px `--ring` outline outside the disc; disabled is the sunk well with a
     * grey dot. Arrow keys move the choice (Radix roving focus).
     */
    function RadioGroup({ className, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Root>) {
      return <RadioGroupPrimitive.Root data-slot="radio-group" className={cn("grid w-full gap-3", className)} {...props} />
    }
    
    function RadioGroupItem({ className, ...props }: React.ComponentProps<typeof RadioGroupPrimitive.Item>) {
      return (
        <RadioGroupPrimitive.Item
          data-slot="radio-group-item"
          className={cn(
            "group/radio peer relative inline-flex aspect-square size-[18px] shrink-0 items-center justify-center rounded-full bg-card shadow-[inset_0_0_0_1.5px_var(--input)] outline-hidden transition-[background-color,box-shadow] duration-150 after:absolute after:-inset-2",
            "enabled:hover:shadow-[inset_0_0_0_1.5px_var(--anibt-wash-line)]",
            "data-[state=checked]:bg-anibt-candy-edge data-[state=checked]:bg-(image:--anibt-candy) data-[state=checked]:shadow-[0_1px_0_var(--anibt-candy-edge)]",
            "focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:outline-solid",
            "aria-invalid:outline-2 aria-invalid:outline-offset-2 aria-invalid:outline-anibt-danger-fill aria-invalid:outline-solid",
            "disabled:cursor-not-allowed disabled:bg-muted disabled:shadow-[inset_0_0_0_1.5px_var(--border)] disabled:data-[state=checked]:bg-anibt-deep2 disabled:data-[state=checked]:bg-none disabled:data-[state=checked]:shadow-[inset_0_0_0_1.5px_var(--border)]",
            className
          )}
          {...props}
        >
          <RadioGroupPrimitive.Indicator data-slot="radio-group-indicator" className="flex items-center justify-center">
            <span className="block size-2 animate-anibt-pop rounded-full bg-white group-disabled/radio:bg-muted-foreground" />
          </RadioGroupPrimitive.Indicator>
        </RadioGroupPrimitive.Item>
      )
    }
    
    export { RadioGroup, RadioGroupItem }

用法

用法
import { Field, FieldLabel } from "@/components/ui/field"
import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"

<RadioGroup defaultValue="1080p">
  <Field orientation="horizontal">
    <RadioGroupItem value="1080p" id="q-1080" />
    <FieldLabel htmlFor="q-1080">1080p</FieldLabel>
  </Field>
  <Field orientation="horizontal">
    <RadioGroupItem value="720p" id="q-720" />
    <FieldLabel htmlFor="q-720">720p</FieldLabel>
  </Field>
</RadioGroup>

两三个短选项横着排、而且是视图或筛选时,用 Segmented Control;选项需要说明时用下面的选择卡。

选择卡

下载方式

FieldLabel 包住横排的 Field:整张卡都能点,选中的卡是粉色淡底加粉边。禁用的选项字变灰、悬停不变色。

状态

纸面圆点加 1.5px input 色内边,悬停变粉;选中是糖果渐变加一个弹入的白点。焦点是 2px ring 色轮廓;禁用是下沉的浅底、灰点。方向键在选项间移动并选中(Radix 的 roving focus),整组只占一个 Tab 位置。

属性

RadioGroup
valuestring默认 —受控的选中值
defaultValuestring默认 —非受控的初始值
onValueChange(value: string) => void默认 —选中改变时调用
namestring默认 —放进 form 时提交的字段名
disabledboolean默认 —整组禁用
RadioGroupItem
valuestring默认 —这一项的值
disabledboolean默认 —只禁用这一项