Featuring Design System

$css Prop

Rainbow Sprinkles 기반의 $css prop으로 토큰 기반 스타일링하기

$css prop은 Featuring Design System의 핵심 스타일링 API입니다. Rainbow Sprinkles를 기반으로, 디자인 토큰 값과 임의 CSS 값을 하나의 prop에서 사용할 수 있습니다.

기본 사용법

모든 레이아웃 컴포넌트(Box, Flex, HStack, VStack, Center, Grid, Typo)와 Button 컴포넌트에서 $css prop을 사용할 수 있습니다.

<Box $css={{
padding: '$spacing-400',
borderRadius: '$radius-200',
backgroundColor: '$background-1',
color: '$text-1',
}}>
Hello World
</Box>

토큰 값 vs 임의 값

$css prop은 토큰 참조와 임의 CSS 값을 모두 지원합니다. 토큰 이름을 문자열로 전달하면 자동으로 CSS 변수로 변환됩니다.

<Box $css={{
// 토큰 값
padding: '$spacing-400',
borderRadius: '$radius-200',

// 임의 CSS 값
width: '100%',
maxWidth: '480px',
border: '1px solid',
borderColor: '$border-default',
}}>
토큰 + 임의 값 혼합
</Box>

레이아웃 속성

레이아웃 관련 속성은 반응형 조건(mobile/tablet/desktop/wide)을 지원합니다.

Display & Flex

<Flex $css={{
gap: '$spacing-300',
padding: '$spacing-400',
borderRadius: '$radius-200',
border: '1px solid',
borderColor: '$border-default',
}}>
<Box $css={{
  flex: '1',
  padding: '$spacing-300',
  bgColor: '$primary-10',
  borderRadius: '$radius-100',
  textAlign: 'center',
}}>flex: 1</Box>
<Box $css={{
  flex: '2',
  padding: '$spacing-300',
  bgColor: '$primary-20',
  borderRadius: '$radius-100',
  textAlign: 'center',
}}>flex: 2</Box>
<Box $css={{
  flex: '1',
  padding: '$spacing-300',
  bgColor: '$primary-10',
  borderRadius: '$radius-100',
  textAlign: 'center',
}}>flex: 1</Box>
</Flex>

Spacing

<HStack $css={{ gap: '$spacing-300' }}>
<Box $css={{
  padding: '$spacing-200',
  bgColor: '$primary-10',
  borderRadius: '$radius-100',
}}>spacing-200</Box>
<Box $css={{
  padding: '$spacing-400',
  bgColor: '$primary-20',
  borderRadius: '$radius-100',
}}>spacing-400</Box>
<Box $css={{
  padding: '$spacing-600',
  bgColor: '$primary-30',
  borderRadius: '$radius-100',
}}>spacing-600</Box>
</HStack>

Sizing

<Box $css={{
  width: '100%',
  height: '48px',
  minWidth: '200px',
  maxWidth: '640px',
  minHeight: '100vh',
  size: '40px',          // width + height 동시 설정
}} />

Border & Radius

<HStack $css={{ gap: '$spacing-300' }}>
<Box $css={{
  size: '64px',
  bgColor: '$primary-20',
  borderRadius: '$radius-100',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
}}>100</Box>
<Box $css={{
  size: '64px',
  bgColor: '$primary-30',
  borderRadius: '$radius-200',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
}}>200</Box>
<Box $css={{
  size: '64px',
  bgColor: '$primary-40',
  borderRadius: '$radius-full',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  color: 'white',
}}>full</Box>
</HStack>

Grid

<Grid $css={{
gridTemplateColumns: 'repeat(3, 1fr)',
gap: '$spacing-300',
}}>
{[1,2,3,4,5,6].map(i => (
  <Box key={i} $css={{
    padding: '$spacing-400',
    bgColor: '$primary-10',
    borderRadius: '$radius-100',
    textAlign: 'center',
    border: '1px solid',
    borderColor: '$primary-30',
  }}>
    {i}
  </Box>
))}
</Grid>

Typography

<Box $css={{
  fontSize: '14px',
  fontWeight: '600',
  fontFamily: 'var(--global-typography-font-sans)',
  lineHeight: '1.5',
  textAlign: 'center',
  textDecoration: 'underline',
  textTransform: 'uppercase',
  letterSpacing: '-0.02em',
  wordBreak: 'break-word',
  whiteSpace: 'nowrap',
  textOverflow: 'ellipsis',
  overflow: 'hidden',
}} />

Position

<Box $css={{
  position: 'absolute',
  top: '0',
  right: '0',
  bottom: '0',
  left: '0',
  inset: '0',           // top + right + bottom + left
  insetX: '16px',       // left + right
  insetY: '0',          // top + bottom
  zIndex: 10,
}} />

Visual

<Box $css={{
  opacity: 0.8,
  overflow: 'hidden',
  overflowX: 'auto',
  overflowY: 'scroll',
  cursor: 'pointer',
  pointerEvents: 'none',
  userSelect: 'none',
  visibility: 'hidden',
  objectFit: 'cover',
  objectPosition: 'center',
  aspectRatio: '16/9',
}} />

Transform & Transition

<Box $css={{
  transform: 'translateX(-50%)',
  transition: 'all 0.2s ease',
  animation: 'fadeIn 0.3s ease',
  scale: '1.05',
  rotate: '45deg',
  translate: '10px 20px',
}} />

색상 속성

색상 관련 속성은 인터랙티브 조건(hover/active/focus/disabled 등)을 지원합니다.

기본 색상 속성

<HStack $css={{ gap: '$spacing-300' }}>
<Box $css={{
  padding: '$spacing-400',
  bgColor: '$background-1',
  color: '$text-1',
  borderRadius: '$radius-200',
  border: '1px solid',
  borderColor: '$border-default',
}}>background-1</Box>
<Box $css={{
  padding: '$spacing-400',
  bgColor: '$background-2',
  color: '$text-2',
  borderRadius: '$radius-200',
}}>background-2</Box>
<Box $css={{
  padding: '$spacing-400',
  bgColor: '$primary-60',
  color: 'white',
  borderRadius: '$radius-200',
}}>primary-60</Box>
</HStack>

인터랙티브 조건

색상 속성에 객체를 전달하면 상태별 스타일을 지정할 수 있습니다. 아래 박스에 마우스를 올려보세요.

<Box $css={{
padding: '$spacing-400',
borderRadius: '$radius-200',
cursor: 'pointer',
transition: 'all 0.2s ease',
bgColor: {
  default: '$background-1',
  hover: '$primary-10',
  active: '$primary-20',
},
color: {
  default: '$text-1',
  hover: '$primary-60',
},
borderColor: {
  default: '$border-default',
  hover: '$primary-60',
},
border: '1px solid',
elevation: {
  default: '$elevation-2',
  hover: '$elevation-8',
},
}}>
Hover & Click me
</Box>

사용 가능한 조건

조건CSS 선택자설명
default기본 상태
hover&:hover마우스 호버
active&:active클릭 중
focus&:focus-visible키보드 포커스
disabled&:disabled비활성 상태
readOnly&:read-only읽기 전용
focusWithin&:focus-within자식 요소 포커스
groupHover[data-group]:hover &부모 그룹 호버

사용 가능한 토큰 색상

토큰 색상은 이름으로 직접 참조합니다:

글로벌 색상: primary-10primary-100, gray-5gray-90, red-10red-100, blue-10blue-100, green-10green-100, orange-10orange-100, yellow-10yellow-100, purple-10purple-100

시맨틱 색상: background-1background-4, border-default, border-1border-4, text-1text-6, support-error-1support-error-4, support-success-1~support-success-4

특수 값: transparent, currentColor, inherit

className / style 콜백

$css 외에도 상태 기반 className과 style을 사용할 수 있습니다.

<Button.Root
  $css={{ padding: '$spacing-400' }}
  className={(state) => state.disabled ? 'opacity-50' : ''}
  style={(state) => ({
    transform: state.loading ? 'scale(0.98)' : undefined,
  })}
>
  <Button.Text>Submit</Button.Text>
</Button.Root>

다른 스타일링과 함께 사용

$css prop은 기존 className, style과 함께 사용할 수 있습니다. 병합 우선순위는 다음과 같습니다:

  1. $css의 토큰 스타일 (가장 낮음)
  2. $css의 className
  3. 내부 컴포넌트 props
  4. 소비자의 className / style (가장 높음)
<Box
  $css={{ padding: '$spacing-400', bgColor: '$background-1' }}
  className="my-custom-class"
  style={{ border: '2px solid red' }}
>
  Content
</Box>