본문으로 건너뛰기

Sidebar

페이지 내용 옆의 열이며, 창이 좁아져 열을 담을 수 없게 되면 drawer가 됩니다. 실제 <aside>를 렌더링하며 이는 complementary 랜드마크입니다.

tsx
import { List, ListItem, Sidebar } from 'neba';

<Sidebar label="목차">
  <List variant="text">
    <ListItem href="/overview" selected>
      개요
    </ListItem>
    <ListItem href="/components">컴포넌트</ListItem>
  </List>
</Sidebar>;

Props

Prop타입기본값설명
childrenReactNode안에 들어가는 것, 탐색, 필터 패널, 목차
side공통'start' | 'end''start'어느 끝을 차지하는지. 물리적이 아니라 논리적이라 RTL에서 뒤집힙니다. PageLayout 안에서는 어느 자리에 넘겼는지로 이미 정해집니다
widthnumber | stringsize열의 너비. 숫자는 픽셀. resizable일 때는 시작 너비이며, 드래그가 이 값을 덮어씁니다
resizablebooleanfalse안쪽 가장자리를 끌어 너비를 바꿀 수 있게 합니다. 키보드에서는 좌우 화살표
minWidthnumber | string160드래그로 좁힐 수 있는 한계
maxWidthnumber | string480넓힐 수 있는 한계
onResize(width: number) => void끄는 동안 매 걸음, 픽셀 단위로
onResizeEnd(width: number) => void놓을 때 한 번. 너비를 저장해 둘 자리
collapseBelow'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'none'PageLayout이 너비보다 좁아지면 열이 아니라 drawer가 됩니다. PageLayout의 값을 물려받으며, PageLayout 밖에서는 none입니다. 여는 버튼 없이 접히면 사이드바에 닿을 방법이 없기 때문입니다
openbooleandrawer가 열려 있는지. 접힌 뒤에만 의미가 있습니다. PageLayout 안에서는 레이아웃이 이 상태를 가지므로 거기서 다루세요
defaultOpenbooleanfalse레이아웃 밖에서 쓸 때의 처음 상태
onOpenChange(open: boolean) => void열리고 닫힐 때. 어느 쪽이 상태를 갖든 항상 호출됩니다
stickybooleantrue페이지가 지나가는 동안 자리를 지키는지. 헤더 아래에서 시작해 남은 창 높이만큼인 sticky 열이 됩니다
titleReactNodedrawer일 때만 그려지는 제목. 열에는 주위의 페이지가 그것이 무엇인지 말해 주지만, 페이지를 덮은 패널에는 없습니다
variant공통'solid' | 'outline' | 'text''outline'면의 무게. 패널은 색으로 물들지 않습니다
size공통'xs' | 'sm' | 'md' | 'lg' | 'xl''md'기본 너비와 안쪽 여백
color공통'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info''primary'의미론적 색 역할. 임의 색상값은 받지 않습니다
density공통'default' | 'compact''default'여백만 바꿉니다. 높이와 글자 크기는 그대로
elevation공통0 | 1 | 2 | 30그림자 깊이. 0은 그림자 없음
dividerbooleantrue내용을 마주보는 안쪽 가장자리의 헤어라인. 바깥쪽은 창에 닿아 있어 나눌 것이 없습니다
paddedbooleantrue안쪽 여백
labelstringlocale('Sidebar')영역의 이름. 사이드바가 둘인 페이지는 반드시 써야 합니다. 아니면 스크린 리더가 “complementary”라는 영역 두 개를 내놓습니다
localestringPageLayout사이드바가 쓰는 단어의 언어. PageLayout 안에서는 물려받습니다

<aside>의 native 속성은 그대로 전달됩니다. 다만 colortitle은 예외입니다. 공통 축은 prop 규칙에서 설명합니다.

자기 children만 배치합니다. 페이지가 사이드바를 둘러싸도록 하려면 PageLayoutsidebarendSidebar 자리에 넣으세요.

예시

width · size

size가 열의 기본 너비를 정하고(md는 16rem), width가 픽셀 숫자나 CSS 길이로 그것을 덮어씁니다.

resizable

안쪽 가장자리를 끌 수 있게 합니다. minWidthmaxWidth가 범위를 정하고, onResize는 끄는 동안 매 걸음, onResizeEnd는 놓을 때 한 번 호출됩니다. 너비를 저장해 둘 자리입니다. 핸들은 focus를 받는 role="separator"라 좌우 화살표로도 같은 일을 할 수 있습니다.

side

왼쪽·오른쪽이 아니라 startend입니다. 탐색 레일은 어떤 쓰기 방향에서도 자기가 속한 본문 옆에 있기 때문입니다. PageLayout 안에서는 어느 자리에 넣었는지가 정해 주므로 이 prop이 필요 없습니다.

collapseBelow

열이 scrim 위의 Drawer가 되는 너비입니다. focus가 안에 갇히고, Escape로 닫히며, 닫으면 focus가 trigger로 돌아갑니다. 어느 모습이든 children은 문서에 한 번만 존재합니다. title은 drawer일 때만 그려집니다. 열에는 주위의 페이지가 그것이 무엇인지 말해 주지만, 페이지를 덮은 패널에는 없기 때문입니다.

기본값은 PageLayout의 값이며 레이아웃 밖에서는 none입니다. 되돌릴 방법이 없는 채로 접힌 사이드바는 독자가 잃어버린 사이드바이기 때문입니다.

sticky

기본값은 켜짐입니다. 페이지가 스크롤될 때는 header 아래에서 시작해 남은 창 높이만큼인 sticky 열이 되고, 내용만 스크롤될 때는 이미 레이아웃 높이만큼이라 아무것도 달라지지 않습니다.

SidebarTrigger

창이 좁아져 담을 수 없게 된 사이드바를 다시 불러오는 버튼입니다. Headerbrand 자리, 로고 앞에 두세요.

tsx
import { Header, PageLayout, Sidebar, SidebarTrigger } from 'neba';

<PageLayout header={<Header brand={<SidebarTrigger />} />} sidebar={<Sidebar>…</Sidebar>}>
  페이지
</PageLayout>;
Prop타입기본값설명
side공통'start' | 'end''start'레이아웃의 두 사이드바 중 어느 쪽을 여는지
collapseBelow'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'none'PageLayout버튼이 나타나는 너비. 사이드바가 접히는 그 너비이며, PageLayout에서 정하는 것이 맞습니다
iconReactNode햄버거글리프. 기본은 세 줄
labelstringlocale('Open sidebar')하는 일을 말로. 기본값은 열림 상태에 따라 “사이드바 열기”와 “사이드바 닫기”
localestringPageLayout그 단어의 언어

IconButton이 받는 나머지 prop은 그대로 전달됩니다. 열 대상이 있으려면 PageLayout 안에 있어야 하며, 밖에서는 아무것도 그리지 않습니다. breakpoint 이상에서는 없어지는 대신 class로 숨겨지므로, 페이지가 도착하고 잠시 뒤에 header 안으로 튀어나오는 일이 없습니다.

접근성

  • <aside>(complementary 랜드마크)를 렌더링하고, label이 없으면 locale의 "사이드바"에 해당하는 단어로 스스로를 이름 짓습니다. 사이드바가 둘인 페이지는 반드시 둘 다 이름을 주어야 합니다.
  • 접힌 상태는 modal dialog입니다. focus가 안에 갇히고, Escape로 닫히며, focus는 trigger로 돌아갑니다.
  • 크기 조절 핸들은 tabindex="0"role="separator"이며 locale이 이름을 붙입니다. 좌우 화살표가 16px씩 움직입니다.
  • locale은 PageLayout에서 물려받으므로 페이지당 한 번만 씁니다.

Released under the MIT License