Featuring Design System
Layout

Box

모든 레이아웃 컴포넌트의 기반이 되는 기본 블록. render prop으로 HTML 요소를 바꾸고, $css prop으로 디자인 토큰 기반 스타일을 적용합니다.

개요

Box는 레이아웃 시스템의 기반 컴포넌트입니다. 기본적으로 <div>를 렌더링하며, render prop으로 렌더링할 HTML 요소를 바꿀 수 있습니다.

  • $css prop — 반응형 레이아웃과 인터랙션 색상을 선언적으로 적용
  • render prop — base-ui의 useRender 기반으로 다형성 렌더링, ref 병합, 이벤트 핸들러 체이닝 지원
  • className / style 콜백 — 컴포넌트 내부 상태를 인자로 받는 함수를 전달해 동적 스타일 처리

내부적으로 useRenderComponent 훅이 base-ui의 useRender + mergeProps를 사용합니다.

언제 사용하나요

  • 스타일을 적용할 컨테이너가 필요할 때
  • render prop으로 시맨틱 HTML(section, article, nav, header 등)을 렌더링해야 할 때
  • 다른 레이아웃 컴포넌트(Flex, Grid, HStack 등)의 자식으로 스타일이 있는 블록이 필요할 때
  • 외부 라이브러리 컴포넌트를 render에 넘겨 디자인 토큰 스타일을 얹고 싶을 때

언제 사용하면 안 되나요

  • 텍스트를 표시할 때 → Typo 사용
  • flex 레이아웃이 필요할 때 → Flex, HStack, VStack, Center 사용
  • grid 레이아웃이 필요할 때 → Grid 사용

접근성

render prop을 활용해 시맨틱 HTML 요소를 렌더링하면 스크린 리더에서 올바른 역할을 전달합니다. role attribute를 추가할 때는 render prop 콜백 안에서 mergeProps로 병합하거나, Box에 직접 attribute로 전달하세요.

Usage

기본 사용법

$css prop에 디자인 토큰을 적용합니다. 토큰 값은 $ 접두사로 시작합니다.

<Box $css={{ padding: '$spacing-400', bgColor: '$background-2', rounded: '$radius-200' }}>
<Typo variant="$body-2">Basic Box</Typo>
</Box>

render prop으로 HTML 요소 변경

render에 JSX 요소를 전달하면 해당 요소로 렌더링됩니다. Box의 props는 그대로 전달되며, ref와 이벤트 핸들러도 병합됩니다.

<Box render={<section />} $css={{ padding: '$spacing-600', bgColor: '$background-3', rounded: '$radius-200' }}>
<Box render={<h2 />} $css={{ marginBottom: '$spacing-200' }}>
  <Typo variant="$heading-4">Section Title</Typo>
</Box>
<Box render={<p />}><Typo variant="$body-2">Section content goes here.</Typo></Box>
</Box>

반응형 스타일

레이아웃 관련 프롭은 mobile, tablet, desktop, wide 조건 객체를 지원합니다. Mobile-first로 동작합니다.

<Box
$css={{
  display: 'flex',
  flexDirection: { mobile: 'column', desktop: 'row' },
  gap: { mobile: '$spacing-200', desktop: '$spacing-400' },
  padding: { mobile: '$spacing-300', tablet: '$spacing-400', desktop: '$spacing-600' },
  bgColor: '$background-2',
  rounded: '$radius-200',
}}
>
<Box $css={{ padding: '$spacing-300', bgColor: '$background-1', rounded: '$radius-100', flexGrow: 1 }}>
  <Typo variant="$body-2">Left</Typo>
</Box>
<Box $css={{ padding: '$spacing-300', bgColor: '$background-1', rounded: '$radius-100', flexGrow: 1 }}>
  <Typo variant="$body-2">Right</Typo>
</Box>
</Box>

인터랙션 색상 (hover / active / focus)

색상 프롭은 default, hover, active, focus, disabled, readOnly, focusWithin, groupHover 조건을 지원합니다. 버튼형 컨테이너를 만들 때 유용합니다.

<Box
render={<button />}
$css={{
  padding: '$spacing-400',
  paddingX: '$spacing-600',
  bgColor: {
    default: '$background-1',
    hover: '$background-3',
    active: '$background-4',
  },
  borderColor: {
    default: '$border-default',
    hover: '$border-1',
  },
  rounded: '$radius-200',
}}
style={{ borderWidth: '1px', borderStyle: 'solid', cursor: 'pointer' }}
>
<Typo variant="$body-2">Hover / Active me</Typo>
</Box>

동적 CSS 값

토큰에 없는 임의 값도 사용할 수 있습니다. dynamicProperties로 어떤 CSS 값이든 받아들입니다.

<Box
$css={{
  width: 'calc(100% - 2rem)',
  maxWidth: '600px',
  height: '200px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  bgColor: '$background-2',
  rounded: '$radius-300',
}}
>
<Typo variant="$body-2">Dynamic width & height</Typo>
</Box>

render prop 콜백 + mergeProps

render에 함수를 전달하면 Box 내부에서 조합된 props를 직접 받을 수 있습니다. mergeProps로 추가 props를 안전하게 병합하세요 — className, event handler 모두 병합됩니다.

<Box
$css={{ padding: '$spacing-400', bgColor: '$background-2' }}
render={(props) => (
  <nav
    {...mergeProps(props, {
      'aria-label': 'Main navigation',
      className: 'custom-nav',
    })}
  />
)}
>
<Typo variant="$body-2">Navigation content</Typo>
</Box>

className / style state callback

classNamestyle에 상태 객체를 인자로 받는 콜백을 전달할 수 있습니다. Box의 BoxState는 현재 비어있지만, 서브클래스 컴포넌트(Button 등)는 이 패턴으로 내부 상태를 노출합니다.

<Box
className={(state) => 'my-box'}
style={(state) => ({ outline: '2px solid transparent' })}
$css={{ padding: '$spacing-400', bgColor: '$background-2', rounded: '$radius-200' }}
>
<Typo variant="$body-2">State callback box</Typo>
</Box>

Props

공통 Props$css, render, className, style는 모든 레이아웃 컴포넌트에서 지원됩니다. useRenderComponent 가이드 →

<div> 요소의 모든 네이티브 속성을 지원합니다. render prop으로 다른 요소를 렌더링할 수 있습니다.

Prop

Type

$css 스타일 프롭

레이아웃 (반응형)

mobile, tablet, desktop, wide breakpoint를 지원합니다.

프롭CSS 속성토큰
displaydisplaynone, flex, inline-flex, block, inline-block, grid, inline-grid
flexDirectionflex-directionrow, column, row-reverse, column-reverse
alignItemsalign-itemsstretch, flex-start, center, flex-end, baseline
justifyContentjustify-contentflex-start, center, flex-end, space-between, space-around, space-evenly
flexWrapflex-wrapnowrap, wrap, wrap-reverse
gapgapspacing 토큰 또는 임의 값
paddingpadding (shorthand)spacing 토큰 또는 임의 값
paddingXpadding-left, padding-rightspacing 토큰 또는 임의 값
paddingYpadding-top, padding-bottomspacing 토큰 또는 임의 값
marginmargin (shorthand)spacing 토큰, auto, 또는 임의 값
marginXmargin-left, margin-rightspacing 토큰, auto, 또는 임의 값
marginYmargin-top, margin-bottomspacing 토큰, auto, 또는 임의 값
widthwidth임의 값
heightheight임의 값
minWidthmin-width임의 값
maxWidthmax-width임의 값
roundedborder-radius (shorthand)radius 토큰 또는 임의 값
positionpositionrelative, absolute, fixed, sticky
overflowoverflowvisible, hidden, scroll, auto
gridTemplateColumnsgrid-template-columns임의 값
gridTemplateRowsgrid-template-rows임의 값

색상 (인터랙션)

default, hover, active, focus, disabled, readOnly, focusWithin, groupHover 조건을 지원합니다.

프롭CSS 속성토큰
colorcolor색상 토큰
bgColorbackground-color (shorthand)색상 토큰
borderColorborder-color색상 토큰
elevationbox-shadow (shorthand)elevation 토큰

스타일

Box는 별도의 기본 스타일을 적용하지 않습니다. 브라우저 기본 <div> 스타일(display: block, box-sizing: border-box)만 적용됩니다. 모든 스타일은 $css prop 또는 className / style로 직접 지정합니다.