본문으로 건너뛰기
내비게이션 / top-nav

TopNav

상단 네비게이션 바 — 데스크톱 inline · 모바일 2-드로어.
내비게이션top-navStatic specimentopnavtop navnavbar상단바
01 · Specimen

먼저 보고, 그다음 계약을 읽습니다

상단 네비게이션 바 — 데스크톱 inline · 모바일 2-드로어.

Workbench 불러오는 중…
Component intent의도와 경계 읽기

logo·items·right 세 슬롯을 받는 상단 바. 데스크톱(≥768px)은 세 슬롯을 가로 inline 으로 배치하고, 모바일(≤767.98px)은 같은 요소를 재배치해 [햄버거] nav items 좌 드로어 · [kebab] right 슬롯 우 드로어로 만든다(한 번에 하나만 열림). 본체는 server-compatible 하고 드로어 상호작용(focus trap·scroll lock·Esc)만 client 로 분리한다. items 를 두 번 렌더하지 않고 단일 요소를 CSS 로 재배치하는 것이 핵심 설계다.

02 · Use

예제

SSOT에 등록된 실제 API 기준 snippet입니다. standalone 배지만 독립 실행 단위이며, fragment는 주변 state·handler 문맥을 생략합니다.

01기본 (logo · items · right)tsxfragment
기본 (logo · items · right)
import { TopNav, ThemeToggle } from "@axe/ui";<TopNav  logo={<a className="axe-topnav__brand" href="/">AXE Labs</a>}  items={[    { href: "/overview", label: "개요", active: true },    { href: "/tokens", label: "Tokens" },  ]}  right={<ThemeToggle />}  mobileLabels={{    right: "테마 도구",    openRight: "테마 도구 열기",    closeRight: "테마 도구 닫기",  }}/>
02CSS-only 데스크톱 바 (비-React)htmlfragment
CSS-only 데스크톱 바 (비-React)
<nav class="axe-topnav" aria-label="Main navigation">  <div class="axe-topnav__left"><a class="axe-topnav__brand" href="/">AXE Labs</a></div>  <div class="axe-topnav__items">    <a class="axe-topnav__item" aria-current="page" href="/overview">개요</a>    <a class="axe-topnav__item" href="/tokens">Tokens</a>  </div>  <div class="axe-topnav__right"><!-- ThemeToggle 등 --></div></nav>
03 · React

Props

TSX 소스가 진실입니다. 주요 export 컴포넌트의 public API만 노출합니다.

이름타입필수기본값설명
logoReact.ReactNode좌측 로고/워드마크 슬롯. .axe-topnav__left 안에 렌더.
itemsNavItem[][]중앙 네비 항목. NavItem = { href: string; label: string; active?: boolean }. 데스크톱 inline, 모바일 좌 드로어로 표시.
rightReact.ReactNode우측 슬롯 (ThemeToggle · NavMenu 등). 모바일에선 kebab(⋯) 우 드로어로.
mobileLabelsPartial<TopNavMobileLabels>모바일 양 drawer의 dialog/open/close accessible label 6개를 locale에 맞게 교체. 미지정 값은 English default.
isActive(href: string) => boolean항목 active 판정 콜백. items[].active 가 우선하며, 없을 때만 이 함수로 resolve. server 단계에서 resolve 되어 client 로는 plain data 만 전달.
mobileDrawerboolean@deprecated v0.6 부터 no-op. 모바일 2-드로어가 새 기본이라 더 분기하지 않는다. 호출부 호환용으로 시그니처만 유지, v0.7 제거 예정.
...restReact.HTMLAttributes<HTMLElement>나머지는 루트 <nav> 로 전파.
04 · Any stack

.axe-* 클래스 계약

React 밖에서도 같은 표면을 그리는 공개 계약입니다. stable은 minor 버전 안에서 이름을 바꾸지 않습니다.

클래스안정성용도
.axe-topnavstablenav 루트 바 (높이 --axe-topnav-height 에 고정).
.axe-topnav__leftstable로고/브랜드 좌측 슬롯.
.axe-topnav__itemsstable중앙 항목 컨테이너 — 데스크톱 inline(가로 fade 스크롤) / 모바일 좌 드로어.
.axe-topnav__itemstable개별 nav 링크.
.axe-topnav__item--activestable활성 항목 (aria-current="page" 와 동등 스타일).
.axe-topnav__rightstable우측 슬롯 — 데스크톱 inline / 모바일 우 드로어. 한 번만 렌더.
.axe-topnav__brandstable로고 슬롯에 텍스트 워드마크를 쓸 때 붙이는 브랜드 식자 클래스 (Logo 컴포넌트 대체 가능).
.axe-topnav__hamburgerinternal모바일 좌 드로어 토글 버튼 (바 좌측, CSS 로 모바일만 표시). JS 구동.
.axe-topnav__kebabinternal모바일 우 드로어 토글 버튼 (바 우측 36px plain 아이콘). JS 구동.
.axe-topnav__drawer-closeinternalmodal drawer 내부의 명시적 닫기 버튼. 키보드·터치·스위치/SR 사용자가 Esc 없이 닫을 수 있음.
.axe-mobile-scriminternal드로어 열림 시 반투명 scrim (공용 모바일 드로어 클래스). 탭 시 닫힘.
비-React 소비 노트
데스크톱 바는 순수 마크업(<nav class="axe-topnav">…)으로 재현 가능. 모바일 2-드로어(햄버거·kebab·scrim·focus trap·scroll lock)는 컴포넌트의 JS 상태(data-open)에 의존하므로 CSS-only 로는 데스크톱 inline 레이아웃만 재현된다.
05 · Inclusive

접근성

키보드, ARIA, 구현 노트를 함께 검토합니다.

Keyboard
  • 데스크톱: 표준 링크 Tab 순회
  • 모바일 드로어 열림 시 Esc 로 닫기
  • 드로어 열림 중 Tab 이 패널 안에서 순환 (focus trap)
  • 열릴 때 첫 focusable 로 focus, 닫힐 때 토글 버튼으로 focus 복원
  • 각 drawer 내부의 명시적 닫기 버튼으로 Esc 없이 닫기
ARIA

루트 <nav aria-label="Main navigation">. 활성 항목 = aria-current="page". 햄버거/kebab 버튼 = aria-expanded + aria-controls(드로어 id) + 내용 기반 동적 aria-label. 열린 패널 = role=dialog + aria-modal이며 배경 sibling은 inert.

Notes

드로어 열림 중 body scroll lock. 토글과 패널의 키보드 focus ring을 보존한다. scrim 탭 또는 항목 클릭 시 닫히며 desktop breakpoint로 커지면 modal/inert 상태를 해제한다.

06 · Judgment

권장 · 지양

권장
  • logo 슬롯엔 홈 링크를 둘 것.
  • active 는 items[].active 또는 isActive 중 하나로 일관되게 지정.
  • right 슬롯은 항목이 아닌 계정/테마 등 보조 액션에 사용.
지양
  • mobileDrawer prop 에 의존하지 말 것 (no-op, v0.7 제거 예정).
  • items 를 밖에서 별도로 다시 렌더하지 말 것 — 모바일 드로어가 같은 요소를 재배치한다.
검색창을 열면 컴포넌트 인덱스를 불러옵니다.