# Radio Group URL: /lynx/components/radio-group Source: https://github.com/daangn/seed-design/blob/dev/docs/content/lynx/components/radio-group.mdx 사용자가 여러 옵션 중 하나만 선택할 수 있게 하는 라디오 그룹 컴포넌트입니다. Lynx Engine 최소 버전: 3.6 사용 가능 버전: @seed-design/lynx-react@0.1.0, @seed-design/lynx-css@0.1.0 ## Preview ```tsx import "./styles"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( ); } ``` ## Installation - npm: npx @seed-design/cli add ui:radio-group - pnpm: pnpm dlx @seed-design/cli add ui:radio-group - yarn: yarn dlx @seed-design/cli add ui:radio-group - bun: bun x @seed-design/cli add ui:radio-group ## Usage `RadioGroup`은 선택 상태와 함께 Field의 안내 정보를 표시합니다. `label`, `labelWeight`, `indicator`, `showRequiredIndicator`, `description`, `errorMessage`를 사용할 수 있습니다. ```tsx import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export function ContactMethod() { return ( ); } ``` `invalid`가 `true`이고 `errorMessage`가 있으면 화면에는 `description` 대신 오류 메시지를 표시합니다. ## Props ### `RadioGroup` ### `RadioGroupItem` ### `Radiomark` ## 접근성 `RadioGroup`은 기본적으로 접근성 요소이며 `accessibility-role-description="radiogroup"`을 사용합니다. 그룹이 비활성 상태이면 `accessibility-traits="disabled"`도 전달합니다. Registry `RadioGroup`에 문자열 `label`을 전달하면 같은 내용을 `accessibility-label`에도 연결합니다. `RadioGroupItem`은 기본적으로 `accessibility-role-description="radio"`를 사용합니다. 선택 상태는 `accessibility-value`의 `selected` 또는 `not selected`로 전달하며, 비활성 상태는 `accessibility-traits="disabled"`로 전달합니다. 문자열 `label`을 사용하면 Registry 래퍼가 그 값을 항목의 `accessibility-label`로 연결합니다. `label`에 문자열이 아닌 콘텐츠를 넣거나 컴파운드 API를 직접 조합할 때는 각 항목에 `accessibility-label`을 명시하세요. 필요하면 모든 기본 접근성 prop을 직접 덮어쓸 수 있습니다. ## Examples ### Sizes ```tsx import "./styles"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( ); } ``` ### Tones #### Brand ```tsx import "./styles"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( ); } ``` #### Neutral ```tsx import "./styles"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( ); } ``` ### Weights React의 항목별 `weight`와 달리 Lynx의 `weight`는 그룹 단위 prop입니다. 아래 예제는 굵기마다 그룹을 나눕니다. 두 그룹은 같은 제어 값을 공유하므로 두 항목 중 하나만 선택됩니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [value, setValue] = useState("regular"); return ( ); } ``` ### Long Label Lynx의 `size`도 그룹 단위 prop입니다. 아래 예제는 크기마다 그룹을 나눕니다. 두 그룹은 같은 제어 값을 공유하므로 두 항목 중 하나만 선택됩니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; const longLabel = "Consequat ut veniam aliqua deserunt occaecat enim occaecat veniam et et cillum nulla officia incididunt incididunt. Sint laboris labore occaecat fugiat culpa voluptate ullamco in elit dolore exercitation nulla."; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [value, setValue] = useState("medium"); return ( ); } ``` ### Disabled `RadioGroup`의 `disabled`는 그룹 전체를 비활성화합니다. 개별 `RadioGroupItem`도 따로 비활성화할 수 있습니다. ```tsx import "./styles"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( ); } ``` ### Listening to Value Changes `RadioGroup`의 `onValueChange`로 선택 값 변경을 감지할 수 있습니다. Controlled 모드에서는 `value`와 `onValueChange`를 함께 사용합니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [count, setCount] = useState(0); const [lastValue, setLastValue] = useState(null); return ( { setCount((previous) => previous + 1); setLastValue(value); }} > onValueChange called: {count} times, last value: {lastValue ?? "-"} ); } ``` ### Use Cases #### React Hook Form React Hook Form은 HTML 폼과 input을 전제로 하므로 Lynx에서는 같은 예제를 실행할 수 없습니다. Lynx에서는 `value`와 `onValueChange`로 선택 값을 제어하세요. 제출과 검증은 앱의 상태 관리와 요청 흐름에서 처리합니다. #### Using `Radiomark` Registry의 `Radiomark`와 `@seed-design/lynx-react`의 컴파운드 API를 함께 사용하면 선택 상태를 공유하면서 항목의 배치를 바꿀 수 있습니다. `Radiomark`는 `RadioGroup.Item` 안에서만 사용할 수 있습니다. ```tsx import "./styles"; import { HStack, RadioGroup as RadioGroupPrimitive, VStack, useSeedClassName, } from "@seed-design/lynx-react"; import { RadioGroup, Radiomark } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); return ( regular medium bold ); } ``` ### RadioGroupField Integration `label`, `description`, `errorMessage` 등의 RadioGroupField 관련 prop을 사용할 수 있습니다. ```tsx import "./styles"; import { useState } from "@lynx-js/react"; import { ActionButton, HStack, VStack, useSeedClassName } from "@seed-design/lynx-react"; import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group"; export default function Example() { const seedClassName = useSeedClassName({ colorMode: "system" }); const [contact, setContact] = useState("email"); const [firstErrorMessage, setFirstErrorMessage] = useState(); const [option, setOption] = useState("option1"); const [secondErrorMessage, setSecondErrorMessage] = useState(); const handleFirstSubmit = () => { setFirstErrorMessage(contact === "email" ? "이메일은 선택할 수 없습니다." : undefined); }; const handleSecondSubmit = () => { setSecondErrorMessage(option === "option1" ? "옵션 1은 선택할 수 없습니다." : undefined); }; return ( 제출 제출 ); } ``` ## Scale Feedback Lynx `RadioGroupItem`은 누르는 동안 `Radiomark`의 배경색을 바꿉니다. React처럼 크기를 줄이지 않으므로 `--seed-radiomark-feedback-scale` CSS 변수도 사용하지 않습니다. ## 웹 버전과의 차이 Lynx `RadioGroup`은 React `RadioGroup`과 다음과 같은 차이가 있습니다. - **오류 안내 렌더링**: React는 오류가 표시될 때 `description`을 접근성 트리에 남기지만, Lynx에는 DOM의 visually hidden 처리 방식이 없어 화면과 접근성 트리에서 `description`을 제외하고 `errorMessage`만 렌더링합니다. - **아이콘 렌더링 방식**: 기본 `RadioGroup.ItemIndicator`는 `` 점으로 렌더됩니다. 사용자 지정 아이콘을 전달하려면 `@karrotmarket/lynx-monochrome-icon`을 별도로 설치하고 단색 아이콘 컴포넌트를 사용하세요. ``를 직접 주입하는 방식은 Lynx에서 지원하지 않습니다. - **이벤트 핸들링**: `onChange` 대신 `onValueChange(value: string)`만 노출합니다. tap 핸들러는 item 내부에서 소유합니다. - **Pressed 상태**: 웹의 크기 축소 대신 내부 press state가 `Radiomark`의 배경색을 바꿉니다. - **렌더링 요소**: HTML ` 사용자 지정 아이콘 패키지는 Registry 기본 설치에 포함되지 않습니다. ```sh bun add @karrotmarket/lynx-monochrome-icon@^1.20.0 ``` ## Lynx 미지원 기능 현재 Lynx 플랫폼 제약으로 다음 기능이 지원되지 않습니다. ### 런타임 모델 차이로 제외 | 기능 | 웹 대응 | 설명 | | --------------------------- | ---------------------- | ------------------------------------------ | | React Hook Form | HTML form 라이브러리 | `value`와 `onValueChange` 및 앱 수준 제출 로직으로 대체 | | `RadioGroupItemHiddenInput` | `` | Lynx에 HTML form 제출 모델 없음 | | `name` | native form field name | Lynx에 native form 제출 모델 없음 | | `focus` / `focusVisible` | 키보드 포커스 | Lynx에 키보드 포커스 개념 없음 | | `onChange` (raw DOM event) | `React.ChangeEvent` | 의미 없음. `onValueChange`로 대체 |