Checkbox | CoUI
LogoCoUI

Checkbox

하나 이상 선택하는 체크박스. 불확정(indeterminate) 상태 지원

Checkbox#

하나 이상의 항목을 선택할 수 있는 체크박스 컴포넌트입니다. 불확정(indeterminate) 상태를 지원합니다.

Live Preview#

사용 시기 (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 상태 변경 콜백
labelString?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 라벨 오른쪽 슬롯
nameString?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
activeBackgroundprimary
checkmarkColoronPrimary
borderColoroutlineVariant
uncheckedBackgroundsurfaceContainer (opacity 0.3)
disabledBackgroundColorsurfaceContainer
disabledBorderColorsurfaceContainer
disabledForegroundColoronSurfaceVariant

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): checkedunchecked 토글
  • 3단계 (tristate: true): checkeduncheckedindeterminatechecked 순환

사용 가이드라인 (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이전 체크박스로 포커스 이동
  • Toggle: on/off 스위치. 즉시 적용되는 설정에 적합
  • Select: 드롭다운 선택. 옵션이 5개 이상이면 Select가 더 적합
  • Form: 폼 컨테이너. 체크박스를 폼 필드로 등록하여 일괄 검증 가능