reopt designreopt design
DocsExploreToolsPricingBuilder
시작하기
개요
시작하기
Next.js 설치
Private install
핵심 개념
아키텍처
컴포지션 패턴
접근성
키보드 패턴
스타일링
테마 시스템
고급 패턴
구축·운영
Skills
AI 연동
CLI (opt surface add)
의존 그래프
도구
Canvas 카탈로그
Theme Builder
Form Builder
템플릿
템플릿
릴리즈
릴리즈 노트
Oopt-ui
reopt designreopt design

AI 시대를 위한 디자인 시스템

  • 문서
  • 가격
  • 릴리즈 노트
  • GitHub
  • 서비스 약관
  • 개인정보처리방침

© 2026 reopt-ai. All rights reserved.

핵심 개념
  1. 문서
  2. /
  3. 핵심 개념
  4. /
  5. 스타일링

스타일링

data-attribute 셀렉터, className 오버라이드, 다크모드, 애니메이션 패턴을 설명합니다.

reopt design · 업데이트 2026년 6월 26일

data-[attr] 셀렉터

opt-ui primitives는 컴포넌트 상태를 data attribute로 노출합니다. Tailwind의 data-* variant로 상태별 스타일을 선언적으로 적용할 수 있습니다.

셀렉터의미사용 예
data-[active-item]Composite 내 현재 활성 아이템data-[active-item]:bg-bg-subtle
data-[focus-visible]키보드 포커스 표시data-[focus-visible]:ring-2
data-[enter]진입 트랜지션 상태data-[enter]:opacity-100
data-[leave]퇴장 트랜지션 상태data-[leave]:opacity-0
data-[open]Disclosure/Dialog 열림 상태[[data-open]>&]:rotate-180
aria-[invalid=true]폼 유효성 검증 실패aria-[invalid=true]:border-red-500

className 오버라이드

Primitive의 핵심 스타일 패턴은 className ?? defaultClass입니다.

tsx
// className을 전달하지 않으면 기본 스타일 적용
<DisclosureTrigger>열기</DisclosureTrigger>

// className을 전달하면 기본 스타일을 완전히 교체
<DisclosureTrigger className="custom-trigger-style">
  열기
</DisclosureTrigger>

tailwind-merge를 사용하지 않는 이유: 병합 시 어떤 스타일이 최종 적용되는지 예측하기 어렵습니다. 완전 교체 방식은 결과가 명확하고, 기본 스타일을 원하면 전달하지 않으면 됩니다.

tsx
// primitives/disclosure.tsx — 실제 구현
const triggerClass =
  "flex w-full items-center justify-between px-4 py-4 text-left ...";

export function DisclosureTrigger({
  className,
  ...props
}: DisclosureTriggerProps) {
  return (
    <AriaDisclosure
      className={className ?? triggerClass}  // 전달 시 교체, 미전달 시 기본
      {...props}
    />
  );
}

다크 모드

OptThemeProvider가 data-theme를 관리하고, Tailwind dark: variant는 [data-theme$="-dark"] 셀렉터로 오버라이드됩니다. 모든 Primitive의 기본 스타일에 dark: variant가 포함되어 있어 별도 설정 없이 다크모드가 동작합니다.

tsx
// 기본 스타일에 dark: variant 포함
const triggerClass =
  "... text-text-primary hover:bg-bg-subtle dark:hover:bg-white/[0.08]/50 ...";

애니메이션 상태

Primitive 레이어가 노출하는 data-enter, data-leave, data-backdrop 속성을 globals.css에서 전역 트랜지션으로 처리합니다.

css
/* globals.css — primitive transition states */

[data-enter] {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 150ms ease-out,
    transform 150ms ease-out;
}

[data-leave] {
  opacity: 0;
  transform: translateY(-4px);
  transition:
    opacity 100ms ease-in,
    transform 100ms ease-in;
}

[data-backdrop] {
  transition: opacity 200ms ease-out;
}

[data-backdrop][data-leave] {
  transition: opacity 150ms ease-in;
}

Disclosure의 콘텐츠 영역은 Tailwind CSS 애니메이션 유틸리티와 data-[enter]/data-[leave]를 함께 사용합니다:

tsx
const contentClass =
  "overflow-hidden " +
  "data-[enter]:animate-in data-[enter]:fade-in data-[enter]:slide-in-from-top-1 " +
  "data-[leave]:animate-out data-[leave]:fade-out";
Previous키보드 패턴CompositeZone, roving tabindex, 방향키 탐색, Esc/Enter 패턴을 예제로 정리핵심 개념
키보드 패턴 페이지로 이동
Next테마 시스템Compound Theme 아키텍처, 5개 프리셋 × light/dark 모드, CSS 변수 체계핵심 개념