Sidebar
الشريط الجانبي<aside> / <nav>
also calledside navigation، side nav، nav sidebar، navigation rail، app shell navigation، side menu، سايدبار، القائمة الجانبية، شريط التنقّل الجانبي، اللوح الجانبي، العمود الجانبي، قائمة لوحة التحكّم
A sidebar is a permanent column along the inline edge of the page that carries app navigation, or content that supports the screen you are on. It is a piece of the layout rather than a layer over it: it shares the same grid as the content, so 240px of sidebar takes exactly 240px off the content area. Nothing about it needs a scrim or a focus trap, and Escape has nothing to close, because the most a user can do is collapse it. It is not a drawer: a drawer is a temporary surface that slides over the content and dismisses on an outside click or on Escape, while a sidebar stays visible with nobody doing anything. A navigation rail is this same column narrowed to icons with the labels hidden, one DOM structure in a second state, even in the systems that ship the rail as a component of its own. And it is not a navbar, which runs horizontally across the page and runs out of room after five or six links, where a sidebar holds dozens of them in groups because a vertical axis can scroll. The practical test: if showing it pushes the content over, it is a sidebar; if it covers the content, it is a drawer.
If you called it…
Live specimen
Interact with the demo. Every part is real and numbered.
الشريط يقاسم هذه المنطقة الصفّ نفسه. طيّه يوسّع المحتوى ولا يكشف طبقة تحته.
Anatomy: every part, named
Hover a row to locate it in the demo above.
Build prompt
How it behaves right-to-left
This section is ours alone.
Which edge it sits on
mirrorsA sidebar on the left in English sits on the right in Arabic, and it moves there by itself when the layout is a grid or a flex row and the column comes first in DOM order, because the inline axis follows dir. Do not write grid-template-columns: 240px 1fr and then reverse it by hand under [dir="rtl"]: the same value is correct both ways as long as the first track is the logical start. What actually breaks is position: fixed with left: 0 and the content pushed over with margin-left: 240px, where nothing mirrors at all, so write inset-inline-start: 0 and margin-inline-start instead.
The border against the content
mirrorsThe line that separates the column from the content is drawn on the edge facing the content, which is border-inline-end and not border-right; with border-right the line jumps to the outer window edge in Arabic and the seam is left bare. The scrollbar of the link list takes that same edge, since a vertical scrollbar sits at the inline end of its box, so it crosses from the right side to the left side when direction flips and a padding-right meant to hold the labels clear of it is left behind: write padding-inline-end, or reserve the room with scrollbar-gutter: stable. If you draw the seam as a shadow instead, box-shadow has no logical form at all, so multiply its horizontal offset by a direction variable to make it mirror.
Indenting nested items
mirrorsChild items inside a group are indented away from the start edge, which in Arabic means to the right, and the indent is padding-inline-start: 2rem on the list item, never padding-left and never margin-left. Do not fake it with blank spaces or a positive text-indent: the spaces land inside the link text and get read out with it, and text-indent moves only the first line, so the shape breaks the moment a label wraps. The vertical guide line that marks the nesting belongs at inset-inline-start: 0 on the group, drawn with a pseudo-element so it travels to the other side with everything else.
The chevron and the hamburger
mirrorsThe collapse chevron is a directional icon: it points at the edge the column folds toward, so it mirrors with the page. The hamburger is three horizontal bars symmetric about the vertical axis, so scaleX(-1) buys nothing while the bars are equal in length and quietly reverses the design as soon as they are not. The working rule: never write [dir="rtl"] svg { transform: scaleX(-1) }, put a dedicated class on chevrons and back arrows only, and leave the section icons (home, user, settings, bell) alone.
The collapse animation
never mirrorsCollapsing is a change of width, not a change of place, and a width has no side to mirror. Doing it with transform: translateX(-190px) gets two things wrong at once: the column leaves by the wrong edge in Arabic, since transforms have no logical form and the offset has to be multiplied by a direction variable, and a gap its full width stays behind in the layout, because a transform never touches the space an element occupies. Animate inline-size instead, or move the transition onto grid-template-columns while both track lists keep the same number of tracks so the values in between can be computed, since a raw --sidebar-w custom property jumps from one value to the other unless you register it with @property and a <length> syntax.
In code
Each row is one framework's word for the same thing. Take the row your project speaks.
See also
Updated · 2026-08-19