Checkbox#
하나 이상의 항목을 선택할 수 있는 체크박스 컴포넌트입니다. 불확정(indeterminate) 상태를 지원합니다.
Live Preview#
default
Web
Flutter
Loading Flutter...
class CheckboxDefaultExample extends StatefulComponent {
const CheckboxDefaultExample({super.key});
@override
State<CheckboxDefaultExample> createState() => _CheckboxDefaultExampleState();
}
class _CheckboxDefaultExampleState extends State<CheckboxDefaultExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Component build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Accept terms',
onChanged: (value) => setState(() => _state = value),
);
}
}
class CheckboxDefaultExample extends StatefulWidget {
const CheckboxDefaultExample({super.key});
@override
State<CheckboxDefaultExample> createState() => _CheckboxDefaultExampleState();
}
class _CheckboxDefaultExampleState extends State<CheckboxDefaultExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Widget build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Accept terms',
onChanged: (value) => setState(() => _state = value),
);
}
}
checked
Web
Flutter
Loading Flutter...
class CheckboxCheckedExample extends StatefulComponent {
const CheckboxCheckedExample({super.key});
@override
State<CheckboxCheckedExample> createState() => _CheckboxCheckedExampleState();
}
class _CheckboxCheckedExampleState extends State<CheckboxCheckedExample> {
CoreCheckboxState _state = CoreCheckboxState.checked;
@override
Component build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Checked',
onChanged: (value) => setState(() => _state = value),
);
}
}
class CheckboxCheckedExample extends StatefulWidget {
const CheckboxCheckedExample({super.key});
@override
State<CheckboxCheckedExample> createState() => _CheckboxCheckedExampleState();
}
class _CheckboxCheckedExampleState extends State<CheckboxCheckedExample> {
CoreCheckboxState _state = CoreCheckboxState.checked;
@override
Widget build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Checked',
onChanged: (value) => setState(() => _state = value),
);
}
}
indeterminate
Web
Flutter
Loading Flutter...
class CheckboxIndeterminateExample extends StatefulComponent {
const CheckboxIndeterminateExample({super.key});
@override
State<CheckboxIndeterminateExample> createState() => _CheckboxIndeterminateExampleState();
}
class _CheckboxIndeterminateExampleState extends State<CheckboxIndeterminateExample> {
CoreCheckboxState _state = CoreCheckboxState.indeterminate;
@override
Component build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Indeterminate',
tristate: true,
onChanged: (value) => setState(() => _state = value),
);
}
}
class CheckboxIndeterminateExample extends StatefulWidget {
const CheckboxIndeterminateExample({super.key});
@override
State<CheckboxIndeterminateExample> createState() => _CheckboxIndeterminateExampleState();
}
class _CheckboxIndeterminateExampleState extends State<CheckboxIndeterminateExample> {
CoreCheckboxState _state = CoreCheckboxState.indeterminate;
@override
Widget build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Indeterminate',
tristate: true,
onChanged: (value) => setState(() => _state = value),
);
}
}
disabled
Web
Flutter
Loading Flutter...
class CheckboxDisabledExample extends StatefulComponent {
const CheckboxDisabledExample({super.key});
@override
State<CheckboxDisabledExample> createState() => _CheckboxDisabledExampleState();
}
class _CheckboxDisabledExampleState extends State<CheckboxDisabledExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Component build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Disabled',
enabled: false,
onChanged: (value) => setState(() => _state = value),
);
}
}
class CheckboxDisabledExample extends StatefulWidget {
const CheckboxDisabledExample({super.key});
@override
State<CheckboxDisabledExample> createState() => _CheckboxDisabledExampleState();
}
class _CheckboxDisabledExampleState extends State<CheckboxDisabledExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Widget build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Disabled',
enabled: false,
onChanged: (value) => setState(() => _state = value),
);
}
}
chain
Web
Flutter
Loading Flutter...
class CheckboxChainExample extends StatefulComponent {
const CheckboxChainExample({super.key});
@override
State<CheckboxChainExample> createState() => _CheckboxChainExampleState();
}
class _CheckboxChainExampleState extends State<CheckboxChainExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Component build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Accept terms',
onChanged: (value) => setState(() => _state = value),
).withStyle(
const CoreCheckboxStyle(
boxBorderColor: CoreColor.token(CoreColors.primary),
boxBorderWidth: CoreStrokeWidth.stroke2,
boxBorderRadius: CoreBorderRadius.all(CoreRadius.radius8),
boxSize: CoreSize.size24,
indicatorLabelGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
class CheckboxChainExample extends StatefulWidget {
const CheckboxChainExample({super.key});
@override
State<CheckboxChainExample> createState() => _CheckboxChainExampleState();
}
class _CheckboxChainExampleState extends State<CheckboxChainExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Widget build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Accept terms',
onChanged: (value) => setState(() => _state = value),
).withStyle(
const CoreCheckboxStyle(
boxBorderColor: CoreColor.token(CoreColors.primary),
boxBorderWidth: CoreStrokeWidth.stroke2,
boxBorderRadius: CoreBorderRadius.all(CoreRadius.radius8),
boxSize: CoreSize.size24,
indicatorLabelGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
사용 시기 (When to Use)#
이 컴포넌트를 사용하세요:
- 여러 옵션 중 하나 이상을 선택할 때 (다중 선택)
- 약관 동의, 옵션 활성화 등 boolean 값을 입력받을 때
- "전체 선택" 같은 부분 선택 상태(indeterminate)를 표현할 때
대신 다른 컴포넌트를 사용하세요:
Toggle: 즉시 적용되는 on/off 스위치가 필요할 때RadioGroup: 여러 옵션 중 하나만 선택해야 할 때Select: 옵션이 많아 드롭다운으로 보여줘야 할 때
기본 사용법 (Basic Usage)#
// 기본 체크박스
Checkbox(
state: CoreCheckboxState.unchecked,
onChanged: handleChanged,
label: '이용약관에 동의합니다',
)
// 체크된 상태
Checkbox(
state: CoreCheckboxState.checked,
onChanged: handleChanged,
label: '알림 받기',
)
// 불확정 상태
Checkbox(
state: CoreCheckboxState.indeterminate,
onChanged: handleChanged,
tristate: true,
label: '전체 선택',
)
// 기본 체크박스
Checkbox(
state: CoreCheckboxState.unchecked,
onChanged: handleChanged,
label: '이용약관에 동의합니다',
)
// 체크된 상태
Checkbox(
state: CoreCheckboxState.checked,
onChanged: handleChanged,
label: '알림 받기',
)
// 불확정 상태
Checkbox(
state: CoreCheckboxState.indeterminate,
onChanged: handleChanged,
label: '전체 선택',
)
Props / Parameters#
| 속성 | 타입 | 기본값 | 설명 |
|---|---|---|---|
state |
CoreCheckboxState |
Flutter 필수 / Web unchecked |
체크 상태 (checked / unchecked / indeterminate) |
onChanged |
ValueChanged<CoreCheckboxState>? |
Flutter 필수 / Web null |
상태 변경 콜백 |
label | String? | null | 라벨 텍스트 |
tristate |
bool |
false |
3단계 상태(불확정) 허용 |
enabled |
bool? |
null |
활성화 여부 (null = onChanged != null) |
variant |
CoreCheckboxVariant |
defaultVariant |
시맨틱 변형 |
size |
CoreComponentSize |
md |
크기 토큰 |
prefix |
Widget? / Component? |
null |
인디케이터 왼쪽 슬롯 |
suffix |
Widget? / Component? |
null |
라벨 오른쪽 슬롯 |
name | String? | null | 폼 필드 이름 |
checkboxStyle |
CoreCheckboxStyle? |
null |
박스 chrome / 중첩 슬롯 묶음 (아래 Style 표 참고) |
focusNode |
FocusNode? |
null |
Flutter 전용 — Web은 브라우저 기본 포커스 |
statesController |
WidgetStatesController? |
null |
Flutter 전용 — Web은 CSS pseudo-class |
controller |
CheckboxController? |
null |
Flutter 전용 — 외부에서 상태를 제어할 때 |
빠른 오버라이드 (Chain)#
이미 만든 Checkbox 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 style 슬롯 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.
class CheckboxChainExample extends StatefulWidget {
const CheckboxChainExample({super.key});
@override
State<CheckboxChainExample> createState() => _CheckboxChainExampleState();
}
class _CheckboxChainExampleState extends State<CheckboxChainExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Widget build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Accept terms',
onChanged: (value) => setState(() => _state = value),
).withStyle(
const CoreCheckboxStyle(
boxBorderColor: CoreColor.token(CoreColors.primary),
boxBorderWidth: CoreStrokeWidth.stroke2,
boxBorderRadius: CoreBorderRadius.all(CoreRadius.radius8),
boxSize: CoreSize.size24,
indicatorLabelGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
class CheckboxChainExample extends StatefulComponent {
const CheckboxChainExample({super.key});
@override
State<CheckboxChainExample> createState() => _CheckboxChainExampleState();
}
class _CheckboxChainExampleState extends State<CheckboxChainExample> {
CoreCheckboxState _state = CoreCheckboxState.unchecked;
@override
Component build(BuildContext context) {
return Checkbox(
state: _state,
label: 'Accept terms',
onChanged: (value) => setState(() => _state = value),
).withStyle(
const CoreCheckboxStyle(
boxBorderColor: CoreColor.token(CoreColors.primary),
boxBorderWidth: CoreStrokeWidth.stroke2,
boxBorderRadius: CoreBorderRadius.all(CoreRadius.radius8),
boxSize: CoreSize.size24,
indicatorLabelGapStyle: CoreGapStyle(size: CoreSpace.space12),
),
);
}
}
스타일 시스템 — checkboxStyle#
Checkbox 의 box chrome / 슬롯 미세 조정은 단일 checkboxStyle
(CoreCheckboxStyle) 으로 흐릅니다. 시맨틱 enum (variant,
size) 은
위젯 파라미터.
Checkbox(
variant: CoreCheckboxVariant.defaultVariant,
size: CoreComponentSize.md,
state: CoreCheckboxState.checked,
onChanged: handleChange,
label: '동의함',
checkboxStyle: CoreCheckboxStyle(
boxBorderColor: CoreColor.token(CoreColors.outline),
boxActiveColor: CoreColor.token(CoreColors.primary),
boxBorderRadius: CoreBorderRadius.all(CoreRadius.radius4),
indicatorLabelGapStyle: CoreGapStyle(size: CoreSpace.space8),
checkmarkIconStyle: CoreIconStyle(
size: CoreSize.size16,
color: CoreColor.token(CoreColors.onPrimary),
),
labelStyle: CoreTextStyle(fontWeight: CoreFontWeight.semiBold),
),
)
CoreCheckboxStyle 필드#
| 필드 | 타입 | 설명 |
|---|---|---|
boxBackgroundColor |
CoreColor? |
Box background fill colour override (idle / unchecked state). |
boxActiveColor |
CoreColor? |
Box background fill colour when checked. |
boxBorderColor |
CoreColor? |
Box border stroke colour override. |
boxBorderWidth |
double? |
Box border stroke width override (logical px, pre-scaling). |
boxBorderRadius |
CoreBorderRadius? |
Box border radius override. |
boxSize |
double? |
Box size (width = height) override (logical px). |
checkmarkSize |
double? |
Checkmark glyph icon size override (logical px).
null
falls back to [defaultsBySize] for the widget's size + any nested
checkmarkIconStyle.size
override.
|
indeterminateSize |
double? |
Indeterminate inner-square side length override (logical px).
null
falls back to [defaultsBySize] for the widget's size.
|
indicatorLabelGapStyle |
CoreGapStyle? |
Nested [CoreGapStyle] slot for the gap between the checkbox indicator (box) and the label / prefix / suffix slot — forwarded straight to the
Gap
widget that separates the slots.
null
defers to [defaultsBySize] for the widget's size, then to [defaultIndicatorLabelGapStyle].
|
transitionDuration |
Duration? |
State-change transition duration override (box colour fade + glyph slot scale / opacity).
null
defers to [defaultTransitionDuration].
|
checkmarkIconStyle |
CoreIconStyle? |
Checkmark icon style override (size / colour).
No
defaultCheckmarkIconStyle
, deliberately — this slot's two halves already have defaults, on two different axes.
Both resolvers build the slot's base themselves as
CoreIconStyle(size: checkmarkSize).merge(merged.checkmarkIconStyle)
, where the size comes from
defaultsBySize[size].checkmarkSize
and the colour is left unset so the per-variant
defaultsByVariant[variant].checkmarkColor
can supply it. A flat constant here would have to pick one of each and would override both tables: a
size
contradicts the six size-keyed values, and a
colour
is worse than wrong — Flutter's
checkmarkIconStyle.color ?? variantStyle.checkmarkColor
would stop reaching the variant token, and on Web the
checkmarkIconStyle.color == null
test that chooses between the
text-<token>
utility class and an inline colour would flip to inline for every checkbox, dropping the class that carries the dark-mode CSS variable.
|
clickableStyle |
CoreClickableStyle? |
Nested [CoreClickableStyle] slot for the composed
Clickable
(press scale / durations / focus ring / disabled opacity). Merged on top of [defaultClickableStyle] and raw-forwarded — the Clickable's own resolver fills the remaining defaults.
|
labelStyle |
CoreTextStyle? |
Label text style override. |
descriptionStyle |
CoreTextStyle? |
Description text style override — the supporting line under the label.
null
defers to [defaultsBySize] for the widget's size (which carries only the
fontSize
step), then to [defaultDescriptionStyle] for the role and colour.
|
labelDescriptionGapStyle |
CoreGapStyle? |
Nested [CoreGapStyle] slot for the vertical gap between the label and the description below it.
null
defers to [defaultLabelDescriptionGapStyle].
|
CoreCheckboxStyle 변형별 기본값 (CoreCheckboxVariantStyle)#
| 필드 | defaultVariant |
|---|---|
activeBackground | primary |
checkmarkColor | onPrimary |
borderColor | outlineVariant |
uncheckedBackground | surfaceContainer (opacity 0.3) |
disabledBackgroundColor | surfaceContainer |
disabledBorderColor | surfaceContainer |
disabledForegroundColor | onSurfaceVariant |
Resolve chain#
design system default for variant
→ CoreCheckboxTheme.style
→ CoreCheckboxTheme.variantStyles[widget.variant]
→ 부모 컴포넌트 슬롯 오버라이드
→ widget.checkboxStyle
변형 (Variants)#
상태#
// 체크됨
Checkbox(
state: CoreCheckboxState.checked,
label: '선택됨',
onChanged: handleChanged,
)
// 불확정
Checkbox(
state: CoreCheckboxState.indeterminate,
label: '일부 선택',
onChanged: handleChanged,
)
// 비활성화
Checkbox(
state: CoreCheckboxState.unchecked,
enabled: false,
label: '비활성',
onChanged: handleChanged,
)
동작 스펙 (Behavior)#
상태 전환#
-
2단계 (
tristate: false):checked↔unchecked토글 -
3단계 (
tristate: true):checked→unchecked→indeterminate→checked순환
사용 가이드라인 (Usage Guidelines)#
✅ Do#
체크박스에 항상 라벨을 제공하세요.
Checkbox(
state: CoreCheckboxState.unchecked,
onChanged: handleChanged,
label: '마케팅 이메일 수신에 동의합니다',
)
라벨 영역도 클릭 가능하여 조작이 쉬워집니다.
❌ Don't#
라벨 없이 체크박스만 두지 마세요.
Checkbox(
state: CoreCheckboxState.unchecked,
onChanged: handleChanged,
)
체크박스의 목적을 알 수 없고, 작은 영역만 클릭 가능합니다.
✅ Do#
긍정형 라벨을 사용하세요.
Checkbox(label: '알림 받기', state: CoreCheckboxState.unchecked, onChanged: handleChanged)
체크 = 활성화가 직관적입니다.
❌ Don't#
부정형 라벨을 사용하지 마세요.
Checkbox(label: '알림 받지 않기', state: CoreCheckboxState.unchecked, onChanged: handleChanged)
체크하면 "받지 않기"가 되어 이중 부정으로 혼란스럽습니다.
접근성 (Accessibility)#
키보드 인터랙션#
| 키 | 동작 |
|---|---|
Space | 체크박스 토글 |
Tab | 다음 체크박스로 포커스 이동 |
Shift+Tab | 이전 체크박스로 포커스 이동 |