Collapsible sidebar

접이식 사이드바

A panel that toggles between a full, labeled sidebar and a narrow, icon-only rail.

Also known as: Collapsible navExpandable sidebar
···
html
<div class="csw" id="csw">
  <nav class="csnav" id="csnav" aria-label="주요 메뉴">
    <button class="cstoggle" id="cstoggle" aria-expanded="true" aria-controls="csnav" aria-label="사이드바 접기">«</button>
    <a href="#" aria-current="page"><i>⌂</i><span>홈</span></a>
    <a href="#"><i>⌕</i><span>검색</span></a>
    <a href="#"><i>☺</i><span>내 정보</span></a>
  </nav>
  <div class="cscontent"><div class="csbar" style="width:70%"></div><div class="csbar" style="width:44%"></div></div>
</div>
css
.csw{position:absolute;inset:0;display:flex}
.csnav{width:120px;background:var(--surface);border-right:1px solid var(--line);display:flex;flex-direction:column;gap:4px;padding:8px;transition:width .28s ease;flex:none}
.csw[data-collapsed] .csnav{width:44px}
.cstoggle{align-self:flex-end;width:24px;height:24px;border:0;background:none;color:var(--muted);font-size:11px;cursor:default;margin-bottom:6px;transition:transform .28s}
.csw[data-collapsed] .cstoggle{transform:rotate(180deg)}
.csnav a{display:flex;align-items:center;gap:9px;padding:7px 8px;border-radius:7px;color:var(--muted);text-decoration:none;font-size:11px;white-space:nowrap;overflow:hidden}
.csnav a[aria-current]{background:color-mix(in srgb, var(--accent) 14%, transparent);color:var(--accent)}
.csnav a i{font-style:normal;width:16px;text-align:center;flex:none}
.csnav a span{transition:opacity .28s}
.csw[data-collapsed] .csnav a span{opacity:0}
.cscontent{flex:1;padding:14px;display:grid;gap:9px;align-content:start}
.csbar{height:9px;border-radius:5px;background:var(--line)}
js
const wrap = document.getElementById('csw'), toggle = document.getElementById('cstoggle');
function setCollapsed(v) {
  wrap.toggleAttribute('data-collapsed', v);
  toggle.setAttribute('aria-expanded', String(!v));
  toggle.setAttribute('aria-label', v ? '사이드바 펼치기' : '사이드바 접기');
}
let auto = true;
toggle.addEventListener('click', () => { auto = false; setCollapsed(!wrap.hasAttribute('data-collapsed')); });
setTimeout(() => {
  setInterval(() => { if (!auto) return; setCollapsed(!wrap.hasAttribute('data-collapsed')); }, 2200);
}, 2600);

Even collapsed, the <nav> landmark and its links must stay in the DOM — when label text visually disappears, each link still needs an accessible name via aria-label or title so a screen reader user doesn't lose the item. The toggle button carries aria-expanded and aria-controls to announce its state and what it operates.

The difference from a navigation rail (see that entry) is whether it transitions at all — a rail is a separate component, fixed at an icon-only narrow width from the start, while a collapsible sidebar is one panel that toggles between a "wide, labeled" state and a "narrow, icon-only" state. The collapsed look can end up resembling a rail, but one is fixed and the other is toggleable. It's also unlike a hamburger menu and drawer — those hide a panel completely off-screen on mobile and bring it back, while a collapsible sidebar on desktop never disappears, only narrows.

Transitioning the width smoothly avoids the layout feeling like it jumps when the state changes.