📌
Dock Menu 구현
- 이번에 처음으로 복잡한 css 처리를 포함한
Dock-Menu를 만들어 보았다. - 이 메뉴는 [테마 설정], [취향 설정]을 위한 도구들이 모여 있으며,
- 디자인에서는 자연스러운 애니메이션을 통해 선택된 아이콘이 바뀌고, 선택된 상태가 유지되도록 설계 했다.

- 기본적으로 메뉴가 호버되면 툴팁이 나타나고 선택된 메뉴는 아이콘이 변경되며, 나머지 메뉴들은
#ffffff으로 바뀐다. 메뉴가 선택되면 메뉴는 자동으로 닫히고 관련된 컴포넌트가 렌더링된다. - 이번에 가장 신경 쓴 부분은 UX와 부드러운 전환이다.
🔎
새로 알 게 된 것
button: 기본적으로 키보드 접근성이 제공돼서 Tab 키로 이동 가능하다.span: 텍스트나 이미지를 감싸기 위해 사용하며, 스타일링을 위해 주로 쓰이는 인라인 요소로 적합하다.aria-label: 웹 접근성을 위한 속성으로, 스크린 리더 같은 보조 기술이 요소를 읽을 때 제공할 텍스트 설명을 설정하는 역할을 한다.
01. 배치 및 스타일링
📌
구상
- 기본 상태 : 기본 도구 메뉴 아이콘만 보인다.
- 호버 : 높이가 커지고, **2개의 추가 아이콘(취향 설정, 테마 설정)**이 위로 슬라이드 되어 나타난다.

메뉴의 초기 사이즈는
76px였으나, 실제 화면에서 테스트해본 결과 크기가 너무 커 보였다. 그래서 일반적인 Dock-Menu는 어떤 사이즈일까 찾아보았다.
-
모바일 :
48~64px -
태블릿/PC :
56~72px -
macOs Dock :
48~64px -
결론적으로는
64px로 변경하였다.
🤔
📍 Dock-Menu 구조
jsx
1
export default function DockMenu({ activeSettings, onSettingsChange }) {
const [isOpen, setIsOpen] = useState(false);
const menuRef = useRef(null);
const getMainButtonBackground = () => {
if (!hasSelectedSetting) {
return 'bg-white';
}
if (!isOpen && activeSettings) {
return 'bg-white';
}
return 'bg-transparent hover:bg-white/50';
};
return (
<div
ref={menuRef}
className={`bottom-menu ... ${isOpen ? 'h-[202px]' : 'h-16'}`}
>
<div className="...">
<button
className={`bottom-menu-icon group absolute ${getMainButtonBackground()}`}
onClick={() => setIsOpen(!isOpen)}
aria-label="도구 메뉴 열기"
>
<img src={isOpen ? dockMenuNoselectIcon : dockMenuIcon} />
</button>
<div className={`bottom-menu-content transition-all duration-100 ${isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'}`}>
{['preference', 'theme'].map((setting, index) => (
<button
key={setting}
onClick={() => onSettingsChange(setting)}
className={`bottom-menu-icon group absolute bottom-[${68 + index * 70}px] ${activeSettings === setting ? 'bg-white' : 'bg-transparent hover:bg-white/50'}`}
>
<img src={activeSettings === setting ? selectedIcons[setting] : unselectedIcons[setting]} />
<span className="... opacity-0 group-hover:opacity-100 transition-opacity">
{setting === 'preference' ? '취향 설정하기' : '테마 설정하기'}
</span>
...
}(1)ㅤ메뉴의 동작 및 상태에 따른 스타일링
- 메뉴가 열리면
bottom-menu의 높이가 확장되며, 닫히면 기본 상태로 돌아간다. - Dock-Menu 버튼 클릭시
setIsOpen(true)로 메뉴를 열고 다시 클릭 시setIsOpen(false)로 닫는다. pointer-events-none: 메뉴가 닫혀있을 때 사용자가 메뉴 항목을 클릭할 수 없도록 설정getMainButtonBackground: 사용자가 특정 메뉴를 활성화하면 그 메뉴의 배경이bg-white로 변경되고 다른 메뉴는bg-transparent로 설정하여 어떤 메뉴가 활성화되어있는지 쉽게 알 수 있게 했다.
(2)ㅤ하위 메뉴 아이템
- 각 설정 버튼
preference와theme는absolute로 위치가 고정되어 있고 메뉴가 열리면 버튼들이 각 위로 배치헸다. transition-opacity와group-hover:opacity-100을 사용하여hover시 이미지의 투명도가 변경되도록 했다. 이로 인해 호버 시 좀 더 직관적인 구분이 가능하도록 했다.hover하면 해당 메뉴의 툴팁이 나타나도록group-hover:opacity-100 transition-opacity효과를 추가
02. 상태 관리 및 로직 구현
Dock-Menu의 열림 상태 및 선택된 설정을 관리하기 위해
zustand활용

jsx
1
const [isOpen, setIsOpen] = useState<boolean>(false);
const [hasSelectedSetting, setHasSelectedSetting] = useState<boolean>(false);
jsx
1
const handleSettingClick = (setting: string) => {
if (setting === activeSettings) {
setIsOpen(false);
setHasSelectedSetting(false);
onSettingsChange(null);
} else {
setIsOpen(false);
setHasSelectedSetting(true);
onSettingsChange(setting);
}
};
const handleMainButtonClick = () => {
if (isOpen) {
setIsOpen(false);
onSettingsChange(null);
setHasSelectedSetting(false);
} else {
setIsOpen(true);
}
};isOpen: Dock-Menu의 열림/닫힘 상태를 관리activeSettings: 부모 컴포넌트에서 관리하는 상태로,preference또는theme설정이 선택됨을 관리hasSelectedSetting: 선택 여부 관리handleSettingClick: 이미 선택된 설정을 다시 클릭하면 해당 설정을 비활성화, 다른 설정을 클릭하면 새로운 설정을 활성화handleMainButtonClick: Dock-Menu가 열려있을 때, 클릭하면 닫고 설정을 초기화하고 닫혀있을 때 클릭하면 열리게 설정
03. 사용자 경험 개선
(1)ㅤ자동 닫힘 및 아이콘 변경

👉
UX 개선 포인트
- ✅ㅤ불필요한 클릭 최소화 → 선택 후 자동 닫힘으로 사용자 조작 간소화
- ✅ㅤ시각적 피드백 제공 → 아이콘 변경을 통해 현재 설정 상태를 명확하게 표현
jsx
1
const handleSettingClick = (setting: string) => {
//...
setIsOpen(false);
};
const getCurrentIcon = () => {
if (!hasSelectedSetting) return dockMenuIcon;
if (isOpen) return dockMenuNoselectIcon;
if (activeSettings === 'preference' && !isOpen) return preferenceIcon;
if (activeSettings === 'theme' && !isOpen) return themeIcon;
return dockMenuIcon;
};- 사용자가
preference또는theme을 선택하면 Dock-Menu가 닫히도록 구현 handleSettingClick함수에서setIsOpen(false)호출하여 선택후 자동으로 닫히도록 처리- 닫힌 후 기본 도구 메뉴 아이콘에서
getCurrentIcon함수로 선택한 설정 메뉴 아이콘으로 변경되도록 설정
(2)ㅤDock-Menu 바깥 클릭 시 메뉴 닫기
👉
UX 개선 포인트
- ✅ㅤ사용자 편의성 향상 → 사용자가 직접 메뉴를 닫을 필요 없이 자연스럽게 닫힘
- ✅ㅤ자연스러운 인터랙션 → 바깥 클릭 시 닫히는 동작은 일반적인 UI 패턴과 일치하여 직관적인 경험 제공

jsx
1
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}, []);useRef를 활용해 Dock-Menu 컨테이너를 참조mousedown이벤트 리스너를 추가하여 바깥을 클릭하면 자동으로 닫히도록 구현menuRef.current.contains(event.target as Node)를 검사하여 바깥 클릭 감지 후setIsOpen(false)수행


