OutlinedContainer | CoUI
LogoCoUI

OutlinedContainer

border·radius·padding·shadow·blur 토큰 chrome 으로 child 를 감싸는 박스 프리미티브 (인프라)

OutlinedContainer#

child토큰 기반 chrome(border + radius + optional padding + shadow + blur)으로 감싸는 박스 프리미티브(인프라)입니다. Card·Window·Alert·ChipInput 등 다수 컴포넌트가 이 박스 chrome 위에 쌓입니다. Web 은 <div> + Tailwind 유틸리티, Flutter 는 동일 CoreOutlinedContainerContract 필드를 읽어 양 플랫폼이 default 를 공유합니다.

Live Preview#

사용법#

OutlinedContainer(
  containerStyle: const CoreOutlinedContainerStyle(
    padding: CoreEdgeInsets.all(CoreSpace.space16),
  ),
  child: Text('테두리 컨테이너').bodyMedium,
)

Props#

파라미터타입기본값설명
child Widget / Component? null chrome 안에 배치되는 콘텐츠
containerStyle CoreOutlinedContainerStyle? null backgroundColor·borderColor·borderWidth·borderRadius·padding·shadow·blur 단일 진입점

스타일 시스템 (Style System)#

CoreOutlinedContainerStyle 필드#

필드타입설명
backgroundColor CoreColor? Background fill colour override.
borderColorCoreColor?Border colour override.
borderRadius CoreBorderRadius? Border radius override.
borderWidth double? Border width override (logical px, pre-scaling).
borderStyle CoreOutlinedContainerBorderStyle? Border style override (solid / dashed / dotted / none).
dashLength double? Dash segment length when [borderStyle] is dashed (logical px). null → [defaultDashLength].
dashSpacing double? Gap between dash segments (logical px). null → [defaultDashSpacing].
elevation CoreOutlinedContainerElevation? Shadow elevation override. When [boxShadow] is also set, [boxShadow] wins.
boxShadow List<CoreShadowLayer>? Explicit shadow stack, overriding the [elevation]-derived one. The elevation enum can only name three prepared stacks, all of them soft ambient shadows. Some surface treatments are defined by shadows it cannot describe at all: a hard offset shadow has zero blur, and a raised-from-the-page look needs two layers going in opposite directions. This slot takes the stack directly so those are expressible without inventing a new enum member per look.
padding CoreEdgeInsets? Inner padding override. Falls back to [defaultPadding] when null.
surfaceOpacity double? Background opacity multiplier (0.0 – 1.0). Multiplied into the alpha channel of [backgroundColor].
surfaceBlur double? Backdrop blur sigma (logical px). When > 0, applies a BackdropFilter (Flutter) / backdrop-filter: blur (Web).
width double? Explicit width override (logical px). No default, and must not have one. Null is not "width unknown", it is "size to the child" — both platforms branch on it rather than reading a value. Flutter hands the null straight to the container's width: , where it means unconstrained; Web only writes the width declaration inside if (width != null) . A constant here would pin every surface built on this primitive — Card , Alert , Window , every picker panel — to one width, and nothing in the tree asks for that.
height double? Explicit height override (logical px). No default, and must not have one — same branch as [width], on the block axis.
duration Duration? Animation duration for chrome property changes (color / radius / width / height). null or [Duration.zero] means no animation.
clipBehavior CoreClipBehavior? Clip behaviour override.

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

✅ Do#

모든 chrome을 containerStyle 하나로 지정하기

OutlinedContainer(
  containerStyle: const CoreOutlinedContainerStyle(
    borderRadius: CoreBorderRadius.all(CoreRadius.radius12),
    padding: CoreEdgeInsets.all(CoreSpace.space16),
  ),
  child: Text('내용').bodyMedium,
)

background·border·radius·padding·shadow·blur는 모두 containerStyle 단일 슬롯 하나로 흐릅니다 — 바깥에 또 다른 Container/<div>로 같은 chrome을 덧그리면 박스가 이중으로 그려집니다.


❌ Don't#

role/이름이 필요한 자리에 그대로 쓰지 않기

// ❌ role/aria 없이 대화상자·영역처럼 쓰는 컨테이너로 오용
OutlinedContainer(
  child: importantDialogContent,
)

OutlinedContainer는 role도 이름도 포커스 대상도 내보내지 않는 순수 chrome 프리미티브입니다. 영역/대화상자 의미가 필요하면 소비자가 직접 Semantics/attributes로 감싸야 하고, 포커스 표시가 필요하면 FocusOutline을 별도로 합성해야 합니다.

접근성 (Accessibility)#

역할 / Semantics#

자체 role 이 없습니다. Flutter 에는 role 을 부여하는 Semantics 래퍼가 없고, 유일한 semantics 호출은 dashed/dotted 테두리를 그리는 CustomPaint 오버레이를 감싼 ExcludeSemantics 입니다. Web 은 <div> 에 호출자 passthrough 속성만 싣고, dashed 테두리용 <svg> 오버레이에는 aria-hidden="true" 를 붙입니다. landmark·region·group·aria-label 중 어느 것도 양 플랫폼에서 나오지 않습니다.

읽는 사람에게 이는 이 박스가 접근성 트리에 존재하지 않는 것과 같다는 뜻입니다 — 이 표면에 이름이나 영역 의미가 필요하면 소비자가 직접 부여해야 합니다.

키보드#

처리하는 키가 없습니다. Web 은 호출자 eventHandlers 를 그대로 전달하지만 자체적으로는 아무 핸들러도 설치하지 않습니다.

포커스#

포커스 대상이 아니며 어느 플랫폼에서도 traversal 정지점이 되지 않습니다. Flutter 에 FocusNode / Focus / autofocus 가 없고 Web 에 tabindex 가 없습니다. 포커스 링도 그리지 않습니다 — 이 컴포넌트의 style 은 border·radius·shadow·blur 만 해석합니다. 포커스 표시가 필요하면 FocusOutline 을 함께 쓰세요.

스크린 리더#

자기 몫으로 안내되는 것이 없고, 리더는 곧바로 child 로 통과합니다. 장식용 dashed/dotted 테두리는 양 플랫폼 모두 접근성 트리 밖에 유지되므로(Flutter ExcludeSemantics, Web aria-hidden="true") 테두리 스타일이 읽히는 일은 없습니다.

알려진 제약#

  • 순수 chrome 이라 role·이름·설명·포커스 가능성이 전부 없습니다. 이 표면을 region / group / dialog 로 만들어야 한다면 소비자가 직접 주입해야 합니다.
  • 주입 통로가 플랫폼마다 다릅니다 — Web 은 attributes: passthrough 로 role / aria-* 를 얹을 수 있지만, Flutter 생성자는 key · child · containerStyle 만 받습니다. Flutter 쪽에서는 이 표면에 이름이나 role 을 붙일 방법이 아예 없으므로, 필요하면 OutlinedContainer 를 소비자가 자기 Semantics 로 감싸야 합니다.
  • 전환 애니메이션에 aria-busy 나 live region 처리가 없습니다 — Flutter 의 AnimatedContainer chrome 전환은 보조기술에 아무것도 알리지 않습니다. 전환의 모션 축 자체는 전역 접근성 축 에서 다룹니다.