SegmentedControl
Action
2~5개 옵션 중 하나만 고르는 세그먼트 컨트롤.
Usage
2~5개 배타 옵션을 가로로 배치해 즉시 전환(보기/상태/정렬). 페이지 이동 없음
import
import
import { SegmentedControl } from '@mildang/design-system/SegmentedControl';SegmentedControl 하나만 가져오면 SegmentedControl.Root · SegmentedControl.Item 를 그 아래에서 쓸 수 있다.
예제를 복사해 쓸 때 필요한 준비
• @mildang/icons 를 따로 설치한다. DS 패키지에 아이콘 컴포넌트가 포함되지 않는다.
• @mildang/styled-system 은 이 저장소에서 Panda 가 생성하는 산출물이다. 저장소 안에서는 turbo run ship 이후 쓸 수 있고, 패키지 소비자는 자기 Panda 산출물이나 다른 레이아웃 수단으로 바꿔야 한다.
Anatomy
tsx
import { SegmentedControl } from '@mildang/design-system/SegmentedControl';
export default function Example() {
return (
<SegmentedControl>
<SegmentedControl.Item />
</SegmentedControl>
);
}부품
필수 여부
반복
위치
SegmentedControl.Root
SegmentedControl.Item
여러 개 가능
SegmentedControl 안에 옵션마다 둔다.
- SegmentedControl 안에 SegmentedControl.Item을 두 개 이상 배치한다.
API Reference
SegmentedControl Props
Prop
Type
Default
ReactNode
지정 안 함
string
지정 안 함
string
지정 안 함
string
지정 안 함
string | (readonly string[] & string)
지정 안 함
boolean
false
boolean
false
(nextValue: string) => void
지정 안 함
"sm" | "md" | "lg"
md
string
지정 안 함
SegmentedControl.Item
하나의 선택 가능한 세그먼트 항목이다.
Prop
Type
Default
ReactNode
지정 안 함
string
지정 안 함
string
지정 안 함
ReactNode
지정 안 함
boolean
지정 안 함
ReactNode
지정 안 함
ReactNode
지정 안 함
아이콘·카운트 배치
SegmentedControl.Item 은 라벨 앞뒤에 아이콘을, 라벨 뒤에 카운트 배지를 붙일 수 있다.
| prop | 위치 | 설명 |
|---|---|---|
startIcon | 라벨 왼쪽 | 항목을 아이콘으로 먼저 식별시킬 때 |
endIcon | 라벨 오른쪽 | 보조 표시(정렬 방향 등)를 라벨 뒤에 붙일 때 |
count | 라벨 오른쪽(끝) | size="xs" color="blue" 텍스트 칩으로 렌더되는 카운트 배지 |
startIcon·endIcon·count 는 서로 배타적이지 않고 함께 쓸 수 있다.
아이콘·카운트
startIcon(라벨 앞) · endIcon(라벨 뒤) · count(카운트 배지)를 보여줍니다. 셋 다 함께 쓸 수 있습니다.
import { useState } from 'react';
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
import HomeIcon from '@mildang/icons/react/home';
import BookmarkIcon from '@mildang/icons/react/bookmark';
import CalendarIcon from '@mildang/icons/react/calendar';
import BulletListIcon from '@mildang/icons/react/bullet-list';
import CardListIcon from '@mildang/icons/react/card-list';
const SegmentedControlWithIconsExample = () => {
const [startValue, setStartValue] = useState('home');
const [endValue, setEndValue] = useState('list');
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
<div>
<p style={{ marginBottom: 8 }}>startIcon + 라벨</p>
<SegmentedControl
value={startValue}
onValueChange={setStartValue}
aria-label="View with leading icons"
>
<SegmentedControl.Item value="home" startIcon={<HomeIcon />}>
홈
</SegmentedControl.Item>
<SegmentedControl.Item value="bookmark" startIcon={<BookmarkIcon />}>
북마크
</SegmentedControl.Item>
<SegmentedControl.Item value="calendar" startIcon={<CalendarIcon />}>
캘린더
</SegmentedControl.Item>
</SegmentedControl>
</div>
<div>
<p style={{ marginBottom: 8 }}>라벨 + endIcon</p>
<SegmentedControl
value={endValue}
onValueChange={setEndValue}
aria-label="View with trailing icons"
>
<SegmentedControl.Item value="list" endIcon={<BulletListIcon />}>
리스트
</SegmentedControl.Item>
<SegmentedControl.Item value="card" endIcon={<CardListIcon />}>
카드
</SegmentedControl.Item>
</SegmentedControl>
</div>
</div>
);
};
export default SegmentedControlWithIconsExample;
예제
기본 사용
선택지 두세 개를 한 줄에 붙여 즉시 전환합니다 — 목록·카드처럼 같은 데이터를 다르게 보는 자리에 씁니다.
import { SegmentedControl as SegmentedControl, type SegmentedControlProps } from '@mildang/design-system/SegmentedControl';
import { useState } from 'react';
import { css } from '@mildang/styled-system/css';
const STORY_DEFAULT_ARGS = { ...({}), ...({}) } as SegmentedControlProps;
const SegmentedControlBasicExampleRender = (args: SegmentedControlProps) => {
const [value, setValue] = useState('a');
return (
<div className={css({ display: 'flex', flexDirection: 'column', gap: 32 })}>
<SegmentedControl {...args} value={value} onValueChange={setValue} aria-label="Segmented example">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b">Button</SegmentedControl.Item>
<SegmentedControl.Item value="c">Button</SegmentedControl.Item>
<SegmentedControl.Item value="d">Button</SegmentedControl.Item>
<SegmentedControl.Item value="e">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
);
};
export default function SegmentedControlBasicExample(props: Partial<SegmentedControlProps>) {
const mergedProps = { ...STORY_DEFAULT_ARGS, ...props } as SegmentedControlProps;
return SegmentedControlBasicExampleRender(mergedProps);
}
크기
sm·md·lg 의 높이를 비교합니다. 툴바 안에 들어가면 sm, 본문 상단이면 md 가 기준입니다.
import { useState } from 'react';
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
const SegmentedControlSizesExample = () => {
const [largeValue, setLargeValue] = useState('a');
const [mediumValue, setMediumValue] = useState('b');
const [smallValue, setSmallValue] = useState('c');
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 32 }}>
<div>
<p style={{ marginBottom: 8 }}>Large</p>
<SegmentedControl
size="lg"
value={largeValue}
onValueChange={setLargeValue}
aria-label="Large size"
>
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b">Button</SegmentedControl.Item>
<SegmentedControl.Item value="c">Button</SegmentedControl.Item>
<SegmentedControl.Item value="d">Button</SegmentedControl.Item>
<SegmentedControl.Item value="e">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
<div>
<p style={{ marginBottom: 8 }}>Medium</p>
<SegmentedControl
size="md"
value={mediumValue}
onValueChange={setMediumValue}
aria-label="Medium size"
>
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b">Button</SegmentedControl.Item>
<SegmentedControl.Item value="c">Button</SegmentedControl.Item>
<SegmentedControl.Item value="d">Button</SegmentedControl.Item>
<SegmentedControl.Item value="e">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
<div>
<p style={{ marginBottom: 8 }}>Small</p>
<SegmentedControl
size="sm"
value={smallValue}
onValueChange={setSmallValue}
aria-label="Small size"
>
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b">Button</SegmentedControl.Item>
<SegmentedControl.Item value="c">Button</SegmentedControl.Item>
<SegmentedControl.Item value="d">Button</SegmentedControl.Item>
<SegmentedControl.Item value="e">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
</div>
);
};
export default SegmentedControlSizesExample;
비활성 상태
전환할 수 없는 상황에서는 컨트롤 전체를 disabled 로 잠급니다.
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
import { css } from '@mildang/styled-system/css';
// States stories for docs (Default, Active, Active Hover, Hover, Pressed)
const stateWrap = css({ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '8px' });
const SegmentedControlStateActiveExample = () => (
<div className={stateWrap}>
<SegmentedControl size="lg" defaultValue="a" aria-label="Active state">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
);
export default SegmentedControlStateActiveExample;
FullWidth
import { useState } from 'react';
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
const SegmentedControlFullWidthExample = () => {
const [value, setValue] = useState('b');
return (
<div style={{ width: 420 }}>
<SegmentedControl value={value} onValueChange={setValue} fullWidth aria-label="Full width">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b">Button</SegmentedControl.Item>
<SegmentedControl.Item value="c">Button</SegmentedControl.Item>
<SegmentedControl.Item value="d">Button</SegmentedControl.Item>
<SegmentedControl.Item value="e" disabled>
Button
</SegmentedControl.Item>
</SegmentedControl>
</div>
);
};
export default SegmentedControlFullWidthExample;
State/Default
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
import { css } from '@mildang/styled-system/css';
// States stories for docs (Default, Active, Active Hover, Hover, Pressed)
const stateWrap = css({ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '8px' });
const SegmentedControlStateDefaultExample = () => (
<div className={stateWrap}>
<SegmentedControl size="lg" aria-label="Default state">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
);
export default SegmentedControlStateDefaultExample;
State/Active Hover
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
import { css } from '@mildang/styled-system/css';
// States stories for docs (Default, Active, Active Hover, Hover, Pressed)
const stateWrap = css({ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '8px' });
const SegmentedControlStateActiveHoverExample = () => (
<div id="sc-active-hover" className={stateWrap}>
<SegmentedControl size="lg" defaultValue="a" aria-label="Active hover state">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
</SegmentedControl>
</div>
);
export default SegmentedControlStateActiveHoverExample;
State/Hover
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
import { css } from '@mildang/styled-system/css';
// States stories for docs (Default, Active, Active Hover, Hover, Pressed)
const stateWrap = css({ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '8px' });
const SegmentedControlStateHoverExample = () => (
<div id="sc-hover" className={stateWrap}>
<SegmentedControl size="lg" defaultValue="a" aria-label="Hover state">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b" className="hover-target">
Button
</SegmentedControl.Item>
</SegmentedControl>
</div>
);
export default SegmentedControlStateHoverExample;
State/Pressed
import { SegmentedControl as SegmentedControl } from '@mildang/design-system/SegmentedControl';
import { css } from '@mildang/styled-system/css';
// States stories for docs (Default, Active, Active Hover, Hover, Pressed)
const stateWrap = css({ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '8px' });
const SegmentedControlStatePressedExample = () => (
<div id="sc-pressed" className={stateWrap}>
<SegmentedControl size="lg" defaultValue="a" aria-label="Pressed state">
<SegmentedControl.Item value="a">Button</SegmentedControl.Item>
<SegmentedControl.Item value="b" className="press-target">
Button
</SegmentedControl.Item>
</SegmentedControl>
</div>
);
export default SegmentedControlStatePressedExample;