
본 컴포넌트는 Next.js 환경에서 **"트리거의 유연성"**과 **"상태 관리의 자동화"**를 목표로 설계되었습니다. 합성 컴포넌트(Compound Component) 패턴을 적용하여 내부 로직을 캡슐화하면서도 사용자가 자유롭게 레이아웃을 구성할 수 있도록 지원한다.
| 컴포넌트명 | 유형 | 주요 역할 |
|---|---|---|
Dropdown |
Client | Root 컨테이너로, Context를 통해 열림/닫힘 상태를 관리하고 외부 클릭 감지 로직을 수행함 |
DropdownTrigger |
Client | cloneElement를 사용하여 자식 요소에 클릭 핸들러를 주입하고 메뉴를 트리거함 |
DropdownContent |
Client | 상태에 따라 절대 위치(absolute)에 렌더링되며 메뉴 아이템들을 감싸는 패널 역할을 함 |
DropdownItem |
Client | 개별 메뉴 항목으로, 클릭 시 전달된 액션을 실행하고 메뉴를 자동으로 닫음 |
Context API와 useState를 통해 메뉴의 열림/닫힘을 제어하므로 별도의 상태 주입이 불필요하다.useEffect와 useRef를 사용하여 메뉴 외부 영역 클릭 시 자동으로 드롭다운이 닫히도록 UX를 최적화했다.DropdownTrigger 내부에 어떤 리프 노드(Button, Icon, Avatar 등)든 배치할 수 있다.children: React.ReactNode: 트리거로 사용할 요소나 아이템 내부에 표시될 텍스트/아이콘을 전달한다.onClick?: (e: MouseEvent) => void: (Item 전용) 클릭 시 실행할 함수입니다. 실행 후 드롭다운은 자동으로 닫힌다.className?: string: 드롭다운 패널의 위치(예: right-0)나 너비를 커스텀하기 위한 Tailwind 클래스이다.children: React.ReactNode: DropdownItem들의 집합을 전달한다.DropdownTrigger 내부에 이전에 정의한 통합형 Button을 배치하여 일관된 디자인을 유지할 수 있다.
"use client";
import {
Dropdown,
DropdownTrigger,
DropdownContent,
DropdownItem
} from "@/shared/ui/dropdown";
import { Button } from "@/shared/ui/button";
export default function ProfileMenu() {
return (
<Dropdown>
<DropdownTrigger>
<Button variant="outline">계정 설정</Button>
</DropdownTrigger>
<DropdownContent className="w-48">
<DropdownItem onClick={() => console.log("프로필")}>프로필</DropdownItem>
<DropdownItem onClick={() => console.log("설정")}>설정</DropdownItem>
<div className="my-1 h-px bg-slate-200" />
<DropdownItem className="text-red-500" onClick={() => alert("로그아웃")}>
로그아웃
</DropdownItem>
</DropdownContent>
</Dropdown>
);
}