Divider | CoUI
LogoCoUI

Divider

콘텐츠 영역을 구분하는 통일 구분선 컴포넌트

Divider#

콘텐츠 영역을 시각적으로 구분하는 통일 구분선 컴포넌트입니다. Divider는 Flutter/Web 동일한 파라미터 이름을 가지며, 수평/수직 orientation, 두께, 색상, 들여쓰기, 중앙 child 슬롯을 지원합니다.

Live Preview#

사용 시기#

  • 리스트 항목 사이나 섹션 사이에 시각적 경계선이 필요할 때
  • 폼 필드나 메뉴 항목 사이를 구분할 때
  • "또는" 구분선처럼 라벨이 있는 구분선이 필요할 때

기본 사용법#

// 기본 수평 구분선
Divider()

// 수직 구분선 (부모가 높이를 제공해야 함)
SizedBox(
  height: CoreSpace.space64,
  child: const Divider(orientation: .vertical),
)

// 들여쓰기
Divider(
  dividerStyle: CoreDividerStyle(
    indent: CoreSpace.space16,
    endIndent: CoreSpace.space16,
  ),
)

// 라벨이 있는 구분선
Divider(child: Text('OR').bodySmall.onSurfaceVariant)
// 기본 수평 구분선
Divider()

// 수직 구분선 (부모가 높이를 제공해야 함)
div(
  [const Divider(orientation: .vertical)],
  styles: Styles(raw: {'height': '${CoreSpace.space64}px'}),
)

// 들여쓰기
Divider(
  dividerStyle: CoreDividerStyle(
    indent: CoreSpace.space16,
    endIndent: CoreSpace.space16,
  ),
)

// 라벨이 있는 구분선
Divider(child: Text('OR').bodySmall.onSurfaceVariant)

빠른 오버라이드 (Chain)#

이미 만든 Divider 인스턴스에 스타일을 빠르게 덧붙이고 싶다면 withStyle 체인을 쓸 수 있습니다. 생성자의 style 슬롯 인자와 동일하게 동작하지만, 이미 구성된 위젯 위에서 바로 이어 쓸 수 있습니다.

class DividerChainExample extends StatelessWidget {
  const DividerChainExample({super.key});

  @override
  Widget build(BuildContext context) {
    return const Divider().withStyle(
      const CoreDividerStyle(
        color: CoreColor.token(CoreColors.primary),
        thickness: CoreStrokeWidth.stroke4,
        indent: CoreSpace.space24,
        endIndent: CoreSpace.space24,
      ),
    );
  }
}
class DividerChainExample extends StatelessComponent {
  const DividerChainExample({super.key});

  @override
  Component build(BuildContext context) {
    return const Divider().withStyle(
      const CoreDividerStyle(
        color: CoreColor.token(CoreColors.primary),
        thickness: CoreStrokeWidth.stroke4,
        indent: CoreSpace.space24,
        endIndent: CoreSpace.space24,
      ),
    );
  }
}

Props#

속성타입기본값설명
orientation CoreDividerOrientation horizontal 구분선 방향
child Widget? / Component? null 중앙에 표시할 슬롯 ("OR" 등)
dividerStyle CoreDividerStyle? null chrome 단일 진입점 (아래 표 참고)

CoreDividerStyle 필드#

필드타입설명
colorCoreColor?Divider line colour override.
thickness double? Line thickness in logical pixels.
indentdouble?Leading indent in logical pixels.
endIndent double? Trailing indent in logical pixels.
childAlignment CoreDividerChildAlignment? Where the optional centered child sits along the divider main axis. Logical, so start / end follow the reading direction. Only observable when the divider has a child — a childless divider has no label to place.
childPadding CoreEdgeInsets? Padding wrapped around the optional centered child — the resolver / widget applies this along the divider main axis only (orientation-aware). Applied as EdgeInsets.symmetric(...) / CSS padding on the child wrapper — not a sibling gap.

색상 토큰#

기본 색상은 CoreColorScheme.outlineVariant — M3 표준 divider 토큰. 프로젝트 전역 변경은 CoreComponentTheme.dividerstyle 로 설정.

사용 가이드라인 (Usage Guidelines)#

✅ Do#

수직 구분선은 높이가 있는 부모로 감싸기

SizedBox(
  height: CoreSpace.space64,
  child: const Divider(orientation: .vertical),
)

수직 Divider는 내부적으로 height: double.infinity로 선을 그리므로, 부모가 명시적 높이를 주지 않으면 선이 렌더링되지 않거나 레이아웃 오류가 납니다.


❌ Don't#

구분선 의미 전달을 orientation 파라미터에 기대지 않기

// ❌ orientation만 주면 접근성 트리에도 구분선으로 전달될 거라 기대
Divider(orientation: .vertical)

orientation은 레이아웃만 바꿀 뿐 role="separator" / aria-orientation을 emit 하지 않습니다 — 리더에게 구분 의미를 전달하려면 Web은 attributes: {'role': 'separator', 'aria-orientation': 'vertical'}를 직접 넘기고, Flutter는 Semantics로 직접 감싸야 합니다.

접근성 (Accessibility)#

역할 / Semantics#

양 플랫폼 모두 아무 역할도 내보내지 않습니다. Flutter 는 Padding / Row / Column 과 선을 그리는 Container 만 조립하고 어디에도 Semantics 를 감싸지 않습니다. Web 은 rolearia-* 도 없는 평범한 <div> 를 emit 하며, 붙는 속성은 호출자가 넘긴 attributes passthrough 뿐입니다.

orientation (CoreDividerOrientation.horizontal / vertical) 은 레이아웃만 바꾸고 aria-orientation 으로 노출되지 않습니다. 즉 이 선은 접근성 트리에서 구분선으로 안내되지도, 장식 요소로 명시되지도 않은 상태입니다.

키보드#

키 입력을 처리하지 않습니다.

포커스#

포커스를 받지 않습니다 — 양 플랫폼 모두 FocusNode / Focus / tabindex 가 없고 포커스 링도 없습니다.

스크린 리더#

선 자체는 아무것도 읽히지 않습니다. child 슬롯을 쓴 경우(예: "OR" 라벨) 그 자식의 텍스트는 읽히지만, 양옆의 선이 구분선으로 식별되지 않으므로 리더 사용자에게는 구조적 의미 없이 단어 하나가 떠 있는 것으로 들립니다.

알려진 제약#

  • 구분선 의미가 필요하면 소비자가 직접 붙여야 합니다. Web 은 passthrough 로 attributes: {'role': 'separator', 'aria-orientation': 'vertical'} 를 넘길 수 있습니다.
  • Flutter 에는 그런 훅이 없습니다 — Divider 를 소비자 코드에서 Semantics 로 감싸야 합니다.
  • 반대로 순수 장식으로 두고 싶다면 지금 상태로 충분합니다. 아무것도 읽히지 않으므로 추가 작업이 필요 없습니다.

전역으로 적용되는 항목(감소된 모션·고대비·강제 색상 등)은 전역 접근성 축을 참고하세요.

레거시 vs 통일 비교 (Migration Notes)#

이전 버전의 CoUI 를 참조하는 코드에는 순수 얇은 선 전용 컴포넌트인 구버전 클래스가 남아 있을 수 있습니다(옛 이름: Separator). Divider 는 그 기능을 전부 포함하는 상위 집합이라 별도 컴포넌트 없이 하나로 통합되었습니다.

항목구버전 클래스통일 Divider
순수 선
중앙 라벨 슬롯("OR" 등)❌ 없음child
비대칭 여백대칭 여백만indent + endIndent (비대칭 가능)
chrome override 평면 파라미터로 분산 dividerStyle: CoreDividerStyle(...) 단일 슬롯

마이그레이션: 색상 · 두께 파라미터는 dividerStyle 슬롯의 color/thickness 필드로, 대칭 여백은 indent(시작)·endIndent(끝) 로 그대로 옮기면 됩니다 — 위 Props 표를 참고하세요.

같은 얇은 선을 두 컴포넌트로 노출하면 "어느 걸 쓰지" 혼란이 생기므로, 새/수정 코드는 Divider 만 사용하세요.

관련 컴포넌트#

  • Gap — 시각적 선 없이 순수 간격.