RadioGroup
Data Input
여러 라디오를 묶어 하나만 선택하게 하는 그룹.
Usage
배타 선택 묶음. 자식으로 Radio(기본)·RadioBox·RadioCard 중 하나를 골라 밀도를 정한다
import
import
import { RadioGroup } from '@mildang/design-system/Radio';예제를 복사해 쓸 때 필요한 준비
• @mildang/styled-system 은 이 저장소에서 Panda 가 생성하는 산출물이다. 저장소 안에서는 turbo run ship 이후 쓸 수 있고, 패키지 소비자는 자기 Panda 산출물이나 다른 레이아웃 수단으로 바꿔야 한다.
API Reference
RadioGroup Props
Prop
Type
Default
string | (string & readonly string[])
지정 안 함
"ltr" | "rtl"
지정 안 함
boolean
지정 안 함
ReactNode
지정 안 함
boolean
지정 안 함
string
지정 안 함
(value: string) => void
지정 안 함
"horizontal" | "vertical"
vertical
SystemStyleObject
지정 안 함
boolean
지정 안 함
string
지정 안 함
같은 패밀리
@mildang/design-system/Radio 에서 같이 내보내는 컴포넌트다.
구성 구조
Radio 는 단독으로 쓰지 않는다. 항상 RadioGroup 으로 감싸 그룹으로 사용하며, 선택
상태·배치 방향(orientation)·키보드 이동은 RadioGroup 이 관리한다 — 감싸지 않으면
RadioGroupItem must be used within RadioGroup 에러로 렌더가 죽는다. 최소 조합 코드는
아래 "기본 사용" 예제를 참고한다.
RadioGroup— 컨테이너(필수).value/defaultValue·orientation·disabled등 그룹 동작을 담당한다.Radio— 개별 옵션.label·endIcon·description등 표시를 담당한다.RadioBox— 썸네일·설명을 담는 박스형 옵션.RadioGroup안에서Radio대신 쓴다.RadioCard— 제목·설명이 많은 카드형 옵션.RadioGroup안에서Radio대신 쓴다.
여러 항목을 동시에 골라야 하면 Radio 가 아니라 Checkbox 다 — 구분 기준은 Checkbox 문서의 "사용 목적과 선택 기준" 절 하나에서만 다룬다.
기본 사용
세로 배치에 항목별 설명까지 붙인 가장 흔한 형태 — 그룹 자체는 컨텍스트와 배치만 담당합니다.
import type { ComponentProps } from 'react';
import { Radio, RadioGroup } from '@mildang/design-system/Radio';
const STORY_DEFAULT_ARGS = { ...({}), ...({
orientation: 'vertical',
disabled: false,
required: false,
}) } as ComponentProps<typeof RadioGroup>;
const RadioGroupDefaultExampleRender = (args: ComponentProps<typeof RadioGroup>) => (
<RadioGroup {...args} defaultValue="opt1" gap="16">
<Radio value="opt1" label="Option 1" />
<Radio value="opt2" label="Option 2" />
<Radio value="opt3" label="Option 3" />
</RadioGroup>
);
export default function RadioGroupDefaultExample(props: Partial<ComponentProps<typeof RadioGroup>>) {
const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof RadioGroup>;
return RadioGroupDefaultExampleRender(mergedProps);
}
예제
그룹 상태
그룹 단위 상태입니다. disabled 는 자식 전체를 잠그고, invalid 와 errorMessage 는 아래에 HelpText 를 붙입니다.
import type { ComponentProps } from 'react';
import { Radio, RadioGroup } from '@mildang/design-system/Radio';
const STORY_DEFAULT_ARGS = { ...({}), ...({
orientation: 'vertical',
required: true,
invalid: true,
errorMessage: '하나를 선택해주세요.',
}) } as ComponentProps<typeof RadioGroup>;
const RadioGroupInvalidExampleRender = (args: ComponentProps<typeof RadioGroup>) => (
<RadioGroup {...args} gap="16">
<Radio value="opt1" label="Option 1" />
<Radio value="opt2" label="Option 2" />
<Radio value="opt3" label="Option 3" />
</RadioGroup>
);
export default function RadioGroupInvalidExample(props: Partial<ComponentProps<typeof RadioGroup>>) {
const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof RadioGroup>;
return RadioGroupInvalidExampleRender(mergedProps);
}
With RadioBox
import type { ComponentProps } from 'react';
import { RadioBox, RadioGroup } from '@mildang/design-system/Radio';
const STORY_DEFAULT_ARGS = { ...({}), ...({
orientation: 'horizontal',
disabled: false,
required: false,
}) } as ComponentProps<typeof RadioGroup>;
const RadioGroupWithRadioBoxExampleRender = (args: ComponentProps<typeof RadioGroup>) => (
<RadioGroup {...args} defaultValue="a" gap="16">
<RadioBox value="a" title="Option A" description="Description" />
<RadioBox value="b" title="Option B" description="Description" />
<RadioBox value="c" title="Option C" description="Description" />
</RadioGroup>
);
export default function RadioGroupWithRadioBoxExample(props: Partial<ComponentProps<typeof RadioGroup>>) {
const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof RadioGroup>;
return RadioGroupWithRadioBoxExampleRender(mergedProps);
}
With RadioCard
import type { ComponentProps } from 'react';
import { RadioCard, RadioGroup } from '@mildang/design-system/Radio';
const STORY_DEFAULT_ARGS = { ...({}), ...({
orientation: 'vertical',
disabled: false,
required: false,
}) } as ComponentProps<typeof RadioGroup>;
const RadioGroupWithRadioCardExampleRender = (args: ComponentProps<typeof RadioGroup>) => (
<RadioGroup {...args} defaultValue="a" gap="16">
<RadioCard value="a" label="Option A" description="Description" />
<RadioCard value="b" label="Option B" description="Description" />
<RadioCard value="c" label="Option C" description="Description" />
</RadioGroup>
);
export default function RadioGroupWithRadioCardExample(props: Partial<ComponentProps<typeof RadioGroup>>) {
const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as ComponentProps<typeof RadioGroup>;
return RadioGroupWithRadioCardExampleRender(mergedProps);
}
Radio — layouts
import { Radio, RadioGroup } from '@mildang/design-system/Radio';
import { css } from '@mildang/styled-system/css';
// 레이아웃 쇼케이스 헬퍼.
// 핵심: Radio 류 컴포넌트는 자체 고정 너비가 없다 — 폭은 항상 부모가 결정한다.
const layoutStack = css({ display: 'flex', flexDirection: 'column', gap: 32 });
const layoutSection = css({ display: 'flex', flexDirection: 'column', gap: 8 });
const layoutCaption = css({ textStyle: 'caption-md-medium', color: 'neutral.text.lowest' });
const RadioGroupRadioLayoutsExample = () => (
<div className={layoutStack}>
<div className={layoutSection}>
<span className={layoutCaption}>Vertical (기본) — 세로 스택, 각 항목은 라벨 폭</span>
<RadioGroup defaultValue="opt1" orientation="vertical" aria-label="Radio vertical" gap="12">
<Radio value="opt1" label="Option 1" />
<Radio value="opt2" label="Option 2" />
<Radio value="opt3" label="Option 3" />
</RadioGroup>
</div>
<div className={layoutSection}>
<span className={layoutCaption}>Horizontal — 가로 나열</span>
<RadioGroup defaultValue="opt1" orientation="horizontal" aria-label="Radio horizontal" gap="16">
<Radio value="opt1" label="Option 1" />
<Radio value="opt2" label="Option 2" />
<Radio value="opt3" label="Option 3" />
</RadioGroup>
</div>
<div className={layoutSection}>
<span className={layoutCaption}>
부모에 width 320 을 줘도 — Radio 는 라벨 폭으로 hug (늘어나지 않음)
</span>
<RadioGroup
defaultValue="opt1"
orientation="vertical"
aria-label="Radio parent width"
width={320}
gap="12"
>
<Radio value="opt1" label="Option 1" />
<Radio value="opt2" label="Option 2" />
</RadioGroup>
</div>
</div>
);
export default RadioGroupRadioLayoutsExample;
RadioBox — layouts
import { RadioBox, RadioGroup } from '@mildang/design-system/Radio';
import { css } from '@mildang/styled-system/css';
// 레이아웃 쇼케이스 헬퍼.
// 핵심: Radio 류 컴포넌트는 자체 고정 너비가 없다 — 폭은 항상 부모가 결정한다.
const layoutStack = css({ display: 'flex', flexDirection: 'column', gap: 32 });
const layoutSection = css({ display: 'flex', flexDirection: 'column', gap: 8 });
const layoutCaption = css({ textStyle: 'caption-md-medium', color: 'neutral.text.lowest' });
// 같은 컴포넌트를 서로 다른 부모 폭에 나란히 두고 폭이 달라지는 것을 비교하는 행.
const widthCompareRow = css({ display: 'flex', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' });
const RadioGroupRadioBoxLayoutsExample = () => (
<div className={layoutStack}>
<div className={layoutSection}>
<span className={layoutCaption}>① 너비 미지정 · Vertical — 부모(RadioGroup) 폭을 그대로 채운다</span>
<RadioGroup defaultValue="a" orientation="vertical" aria-label="RadioBox fill" gap="12">
<RadioBox value="a" title="Option A" description="Description" />
<RadioBox value="b" title="Option B" description="Description" />
</RadioGroup>
</div>
<div className={layoutSection}>
<span className={layoutCaption}>
② 부모 폭에 따라 달라진다 — 같은 RadioBox, 부모 width 만 200 / 320 으로 다름
</span>
<div className={widthCompareRow}>
<RadioGroup
defaultValue="a"
orientation="vertical"
aria-label="RadioBox width 200"
width={200}
gap="12"
>
<RadioBox value="a" title="Option A" description="Description" />
<RadioBox value="b" title="Option B" description="Description" />
</RadioGroup>
<RadioGroup
defaultValue="a"
orientation="vertical"
aria-label="RadioBox width 320"
width={320}
gap="12"
>
<RadioBox value="a" title="Option A" description="Description" />
<RadioBox value="b" title="Option B" description="Description" />
</RadioGroup>
</div>
</div>
<div className={layoutSection}>
<span className={layoutCaption}>③ Horizontal — 한 줄에 콘텐츠 폭으로 나열</span>
<RadioGroup defaultValue="a" orientation="horizontal" aria-label="RadioBox horizontal" gap="12">
<RadioBox value="a" title="Option A" description="Description" />
<RadioBox value="b" title="Option B" description="Description" />
<RadioBox value="c" title="Option C" description="Description" />
</RadioGroup>
</div>
</div>
);
export default RadioGroupRadioBoxLayoutsExample;
RadioCard — layouts
import { RadioCard, RadioGroup } from '@mildang/design-system/Radio';
import { css } from '@mildang/styled-system/css';
// 레이아웃 쇼케이스 헬퍼.
// 핵심: Radio 류 컴포넌트는 자체 고정 너비가 없다 — 폭은 항상 부모가 결정한다.
const layoutStack = css({ display: 'flex', flexDirection: 'column', gap: 32 });
const layoutSection = css({ display: 'flex', flexDirection: 'column', gap: 8 });
const layoutCaption = css({ textStyle: 'caption-md-medium', color: 'neutral.text.lowest' });
// 같은 컴포넌트를 서로 다른 부모 폭에 나란히 두고 폭이 달라지는 것을 비교하는 행.
const widthCompareRow = css({ display: 'flex', gap: 16, alignItems: 'flex-start', flexWrap: 'wrap' });
const RadioGroupRadioCardLayoutsExample = () => (
<div className={layoutStack}>
<div className={layoutSection}>
<span className={layoutCaption}>① 너비 미지정 · Vertical — 부모(RadioGroup) 폭을 그대로 채운다</span>
<RadioGroup defaultValue="a" orientation="vertical" aria-label="RadioCard fill" gap="12">
<RadioCard value="a" label="Option A" description="Description" />
<RadioCard value="b" label="Option B" description="Description" />
</RadioGroup>
</div>
<div className={layoutSection}>
<span className={layoutCaption}>
② 부모 폭에 따라 달라진다 — 같은 RadioCard, 부모 width 만 200 / 320 으로 다름
</span>
<div className={widthCompareRow}>
<RadioGroup
defaultValue="a"
orientation="vertical"
aria-label="RadioCard width 200"
width={200}
gap="12"
>
<RadioCard value="a" label="Option A" description="Description" />
<RadioCard value="b" label="Option B" description="Description" />
</RadioGroup>
<RadioGroup
defaultValue="a"
orientation="vertical"
aria-label="RadioCard width 320"
width={320}
gap="12"
>
<RadioCard value="a" label="Option A" description="Description" />
<RadioCard value="b" label="Option B" description="Description" />
</RadioGroup>
</div>
</div>
<div className={layoutSection}>
<span className={layoutCaption}>③ Horizontal — 한 줄에 콘텐츠 폭으로 나열</span>
<RadioGroup defaultValue="a" orientation="horizontal" aria-label="RadioCard horizontal" gap="12">
<RadioCard value="a" label="Option A" description="Description" />
<RadioCard value="b" label="Option B" description="Description" />
<RadioCard value="c" label="Option C" description="Description" />
</RadioGroup>
</div>
</div>
);
export default RadioGroupRadioCardLayoutsExample;