본문으로 건너뛰기

ZSRadioGroup

여러 선택지 중 하나만 고르는 목록입니다. 선택지가 화면에 모두 보여야 할 때 씁니다.

플랫폼구현
iOS·AndroidSVG 컨트롤입니다. 라벨을 포함한 줄 전체가 선택 영역입니다.

라디오는 ZSCheckbox와 같은 톤입니다. 고르면 채움 강조라 primary로 채운 원 + 흰 점, 안 고르면 textSecondary 링(지름 20, 링 2)이고, 비활성은 흐린 text입니다. 고른 줄 라벨은 강조 굵기라 색 말고 굵기로도 드러납니다.

줄은 좌우 여백 없이 부모 내용선에 맞고, 최소 높이(iOS 44pt·Android 56dp)가 라벨 있는 ZSCheckbox·ZSSwitch 줄과 같아 한 목록에 섞어도 줄이 맞습니다. 큰 글자로 라벨이 여러 줄이 되면 줄이 늘어납니다. 한 칸 줄(columns 1)은 줄 사이에 border 구분선이 있습니다.

기본 사용법​

import { useState } from 'react';
import { ZSRadioGroup, type ZSRadioOption } from '@0610studio/zs-ui';

const OPTIONS: ZSRadioOption[] = [
{ value: 'email', label: '이메일로 받기' },
{ value: 'sms', label: '문자로 받기' },
{ value: 'none', label: '받지 않기' },
];

function ResponseType() {
const [type, setType] = useState('email');
return <ZSRadioGroup options={OPTIONS} value={type} onValueChange={setType} />;
}

보통은 하나가 선택된 상태로 씁니다(M3). 필수 선택을 따로 검증하는 폼이면 value·defaultValue에 null을 줘 아무것도 고르지 않은 채 시작합니다. 선택지가 5개를 넘으면 ZSSelect를 씁니다.

가로 격자 — columns​

성별·예/아니오처럼 짧은 선택지는 columns로 한 줄에 나란히 둡니다. 칸은 같은 폭이고 줄 사이 구분선은 없습니다.

<ZSRadioGroup options={[{ value: 'male', label: '남아' }, { value: 'female', label: '여아' }]} columns={2} defaultValue={null} onValueChange={setGender} />

Props — ZSRadioGroupProps<T>​

PropTypeDefault설명
optionsZSRadioOption<T>[]Required선택지
valueT | nullundefined선택한 value(제어). null이면 아무것도 고르지 않은 상태
defaultValueT | null첫 선택지비제어 초기값. null이면 고르지 않은 채 시작
onValueChange(value: T, index: number) => voidundefined고른 선택지의 value와 options 안 위치
disabledbooleanfalse전체 비활성
columnsnumber1한 줄에 놓을 선택지 수 — 2 이상이면 같은 폭 칸의 가로 격자
accessibilityLabelstringundefined그룹 이름(무엇을 고르는지, 예: '결제 수단')
styleStyleProp<ViewStyle>undefined
testIDstringundefined항목에는 ${testID}-${value}가 붙습니다

ZSRadioOption<T>​

필드Type설명
valueTonValueChange로 돌려주는 식별자
labelstring보이는 문구
disabledboolean이 항목만 비활성
accessibilityLabelstring스크린 리더 이름. 기본 label
accessibilityHintstring스크린 리더 힌트

T는 string·number입니다(기본 string). ZSRadioGroupProps·ZSRadioOption 타입을 내보냅니다.

const MINUTES: ZSRadioOption<number>[] = [
{ value: 10, label: '10분 전' },
{ value: 30, label: '30분 전' },
{ value: 60, label: '1시간 전' },
];

const [minutes, setMinutes] = useState(10);
<ZSRadioGroup options={MINUTES} value={minutes} onValueChange={setMinutes} />

제어·비제어​

value를 주지 않으면 비제어이고, 처음 선택은 defaultValue(없으면 첫 선택지)입니다.

<ZSRadioGroup options={OPTIONS} defaultValue="sms" onValueChange={(value) => save(value)} />

접근성​

const PAYMENTS: ZSRadioOption[] = [
{ value: 'card', label: '카드', accessibilityHint: '다음 화면에서 카드를 고릅니다' },
{ value: 'phone', label: '휴대폰', accessibilityLabel: '휴대폰 소액결제' },
];

<ZSRadioGroup options={PAYMENTS} accessibilityLabel="결제 수단" value={method} onValueChange={setMethod} />
iOS (VoiceOver)Android (TalkBack)
선택지줄마다 라디오 역할, 이름, 선택 상태줄 전체가 라디오 하나 — 이름, 선택 상태
그룹 이름accessibilityLabelaccessibilityLabel
accessibilityHint이름·상태 다음에 읽습니다이름·상태 다음에 읽습니다
비활성 선택지비활성으로 읽습니다비활성으로 읽습니다

그룹 이름을 언제 읽는지는 플랫폼마다 다릅니다. 선택지 이름만으로 뜻이 통하게 쓰고, 화면에도 그룹 제목을 두는 편이 좋습니다.

관련 문서​