# Side-panel presence and docking in editors You're reading this because the overlay-mode collapse bar permanently covers part of the stage, and we have to choose between (a) reserving a margin for it, (b) a small floating edge tab, (c) a fixed application rail, and (d) panels that can be dragged and docked to either side. [The June report](./editor-side-navigation-patterns.md) asked what a rail click should do. This one asks how a panel stays reachable when it's collapsed, and where it's allowed to live. **Outcome (2026-11-04):** we built `tab` and `none` as recommended, with one change: `strip` now reserves its column in overlay mode instead of keeping today's bar over the center, so it's the reserved strip from option (a). We also went against the advice below and made the tab draggable, under the same lock as sections. The rail and docking stay parked, in [`feature-ideas.md`](./feature-ideas.md). ## TL;DR and recommendation **Build a fixed small tab, plus a "no affordance" option, for collapsed overlay panels. That's (b) without the drag. Leave (c) and (d) parked until a consumer asks for them.** - **The closest prior art is Blender, not VS Code.** Blender can let its Sidebar overlap the 3D viewport, and a hidden region "leaves a little arrow sign" you click to bring it back ([Region Overlap](https://docs.blender.org/manual/en/latest/editors/preferences/interface.html), [Regions, Blender 5.2 LTS](https://docs.blender.org/manual/en/latest/interface/window_system/regions.html)). That is our use case with a shipped answer. - **VS Code doesn't do what overlay mode does.** Its side bars take layout space, and the [request to auto-hide them](https://github.com/microsoft/vscode/issues/3742) has been open since 2016 with 597 upvotes. Treat VS Code as the model for rails and for moving views. For overlays, look at JetBrains, Visual Studio and Blender. - **Our current bar is the outlier.** Every overlay-style product we could source either reserves a strip for the collapsed affordance (JetBrains, Visual Studio, 3ds Max, FlexLayout, as far as their docs show) or shrinks it to something tiny (Blender, Ant). We found nothing that lays a full-height bar over content. - **(a) is more respectable than you think, and still not my first pick.** A reserved strip keeps overlay's main benefit, because opening and collapsing still never resize the center. It costs 20px per side at the normal tier. But an empty reserved strip is the worst version of that idea: if we're going to pay for the column, it should hold icons, and that's (c). - **Dragging the tab along the edge is the part to cut.** We found it only in phone OS shells and a browser extension, and in none of the editors we surveyed. Those shells have no app chrome to host a button. We do. A configurable position solves the collision problem at a fraction of the cost. - **(c) and (d) are separable, and (d) is three different features.** A side-flip setting is cheap. Dragging a whole panel to a side is expensive. A tree of arbitrary splits is a different product. The market-leading library [sells auto-hide and dock-to-edge as paid features](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoHideEdgeGroups.mdx), which says something about where the hard work sits. - **You're not being idealistic about the direction, only the order.** At the commits I checked, [no consumer sets `leftPanelMode` or `rightPanelMode`](#what-consumers-do-today) yet. So the rail and docking have no pull, and overlay itself has none in consumer code yet. ```mermaid flowchart TD A[Collapsed overlay panel covers the stage] --> B{Does the app already have
a toolbar or title bar?} B -->|Yes, and it can host a toggle| C[affordance: none
toggle lives in topToolbars] B -->|No, or the panel must be findable on its own| D[affordance: tab
fixed position, Blender style] D --> E{Does the tab collide
with consumer HUD?} E -->|Yes| F[Configurable offset, not a drag] E -->|Still colliding, across several apps| G[Consider a reserved strip, option a] C --> H{Three or more mutually exclusive
views on one side?} D --> H H -->|Real consumer asks| I[Rail, option c] I --> J{Users ask to rearrange
beyond moving sections?} J -->|Yes| K[Drag rail icons between rails, option d] ``` ## What are these patterns called? There's no single standard vocabulary. A few terms are understood everywhere, and many are one product's branding. For our docs and API, I'd use the terms marked "Common". | Term | Meaning | Status | Source | | --- | --- | --- | --- | | **Overlay** vs **push / inline / inset** | Panel covers the content, or displaces it | Common. Exact words vary | [Fluent's `OverlayDrawer` / `InlineDrawer`](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-drawer/library/README.md), [FlexLayout's "split/overlay"](https://caplin.github.io/FlexLayout/demos/v0.11/examples/borders/) | | **Dock** | Attach a panel to a frame position rather than float it | Common | [Visual Studio](https://learn.microsoft.com/en-us/visualstudio/ide/customizing-window-layouts-in-visual-studio) | | **Float / tear-off / popout** | Detach within the window, or into a separate OS window | Float is common. Popout is mostly web libraries | [Dockview](https://www.dockview.dev/) | | **Auto-hide / pinned / unpinned** | Panel slides away when it loses focus, and a pin keeps it open | Common. Lots of apps use it | [Visual Studio](https://learn.microsoft.com/en-us/visualstudio/ide/customizing-window-layouts-in-visual-studio), [JetBrains](https://www.jetbrains.com/help/idea/viewing-modes.html) | | **Peek** | Temporarily reveal an auto-hidden panel as an overlay | Understood, not formal | [Dockview's auto-hide docs](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoHideEdgeGroups.mdx) | | **Rail / navigation rail** | Permanent narrow icon strip for switching destinations | Common. Material's formal term | [M3 navigation rail](https://m3.material.io/components/navigation-rail/guidelines) | | **Drawer** | Panel that slides in from an edge | Common on web and mobile, and Unreal uses it too | [MUI](https://mui.com/material-ui/react-drawer/), [Unreal](https://dev.epicgames.com/documentation/en-us/unreal-engine/content-browser-in-unreal-engine) | | **Temporary / persistent / mini variant / permanent** | Drawer behaviors | MUI's names, widely recognized | [MUI](https://mui.com/material-ui/react-drawer/) | | **Offcanvas vs icon collapse** | Collapse to nothing, or collapse to an icon strip | shadcn's names, a useful distinction | [shadcn sidebar](https://ui.shadcn.com/docs/components/sidebar) | | **Workspace / layout preset** | Saved arrangement of panels | Common in creative and IDE tools | [Godot](https://docs.godotengine.org/en/stable/tutorials/editor/customizing_editor.html), [Resolve](https://davinciresolveclub.com/davinci-resolve-workspace-layout-presets/) | | **Activity Bar**, **Primary / Secondary Side Bar** | VS Code's rail and panels | Product-specific, widely known | [VS Code](https://code.visualstudio.com/docs/getstarted/userinterface) | | **Tool window bar** ("stripe" informally) | JetBrains' rail. The current docs say "bar" | Product-specific | [JetBrains](https://www.jetbrains.com/help/idea/tool-windows.html) | | **Guide diamond** ("compass" informally) | The drop-target cross shown during a drag | Visual Studio's term | [Visual Studio](https://learn.microsoft.com/en-us/visualstudio/ide/customizing-window-layouts-in-visual-studio) | | **Edge handle / edge tab / zero-width trigger** | Small grab tab on an edge | No standard name. "Handle" is Samsung's, "special trigger" is Ant's | [Samsung](https://www.samsung.com/us/support/answer/ANS00080551), [Ant](https://ant.design/components/layout) | | **Icon dock / collapse to icons** | Panels shrunk into an icon column | Adobe's terms | [Photoshop](https://helpx.adobe.com/photoshop/desktop/get-started/learn-the-basics/collapse-expand-icons.html) | So the answer to the literal question is: VS Code's rail is an "activity bar" or "navigation rail", overlay mode is "overlay" or "auto-hide", and the panel-dragging feature is "docking". What we call the edge bar has no established name, because nobody else really ships it. ## How do other editors keep a collapsed panel reachable? Evidence key: **Docs** means I read it in current vendor docs. **Thread** means a user report on a forum or issue tracker. **Silent** means the docs I read don't say, and I'm not claiming anything. | Product (version where known) | What stays on screen when collapsed | Overlays without resizing the center? | Moving panels; several per side | Evidence | | --- | --- | --- | --- | --- | | **Blender** 5.2 LTS | A small arrow | Yes, Region Overlap | Regions are fixed. Areas split. | [Docs](https://docs.blender.org/manual/en/latest/interface/window_system/regions.html) | | **JetBrains** 2026.2 | Tool window bar with icons, which can itself be hidden | Yes for Undock, which "covers part of the editor". Dock Unpinned shows only when active, but the docs don't say whether it reflows. | Drag icons between bars. Drop below a separator to split. | [Modes](https://www.jetbrains.com/help/idea/viewing-modes.html), [bars](https://www.jetbrains.com/help/idea/new-ui.html) | | **Visual Studio** (docs updated Oct 2026) | Named tabs on the IDE edge | Yes in practice: auto-hide "slides". The doc doesn't discuss reflow, but [Dockview describes the pattern as non-reflowing](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoHideEdgeGroups.mdx). | Drag with guide diamond, anywhere in the frame | [Docs](https://learn.microsoft.com/en-us/visualstudio/ide/customizing-window-layouts-in-visual-studio) | | **VS Code** (Nov 2026) | Activity Bar. It can sit at the top or bottom, or be hidden. | **No.** The layout docs describe no overlay, and [#3742](https://github.com/microsoft/vscode/issues/3742) is still open. | Primary moves by setting or context menu, not by dragging. Secondary is "always positioned opposite". Views drag between them. | [Docs](https://code.visualstudio.com/docs/configure/custom-layout) | | **Unreal** | Drawer buttons on the bottom bar, sidebar tabs | Yes. Drawers are temporary and minimize on focus loss. | Dock in Layout makes a persistent instance. Tabs dock anywhere. | [Docs](https://dev.epicgames.com/documentation/en-us/unreal-engine/content-browser-in-unreal-engine), sidebar tabs from [thread](https://forums.unrealengine.com/t/engines-ui-docking-to-sidebar/1785192) | | **Unity** 6.6 | Windows: silent. Scene overlays collapse to a small control when docked. | Scene overlays yes, and they're inside the 3D view | Tabs drag with an outline preview. Overlays have blue drop zones. | [Windows](https://docs.unity.com/en-us/engine/current/manual/extending-the-editor/customizing-your-workspace), [overlays](https://docs.unity.com/en-us/engine/6000.6/manual/working-with-scenes/scenes-manage-gameobjects/overlays/position-and-display/position-overlay) | | **Godot** (stable docs) | Silent | Silent | A menu moves a dock, or makes it floating. Saved layouts. | [Docs](https://docs.godotengine.org/en/stable/tutorials/editor/customizing_editor.html) | | **Photoshop** (Feb 2026) | Icon dock, with or without labels | Silent on whether expanding reflows. [Auto-collapse exists in "some products"](https://helpx.adobe.com/hk_en/incopy/desktop/get-started/settings-and-preferences/workspace-basics.html). | Drag icons between docks, or out to float | [Docs](https://helpx.adobe.com/photoshop/desktop/get-started/learn-the-basics/collapse-expand-icons.html) | | **Figma** UI3 (Oct 2024 post) | Minimize UI collapses panels. [Users report it collapses both sides together.](https://forum.figma.com/suggest-a-feature-11/bring-back-independent-left-right-panel-collapsing-as-in-ui2-42703) | Only under Minimize UI, Slides grid view and FigJam. Default panels went back to fixed. | Not movable, as far as I found | [Figma blog](https://www.figma.com/blog/our-approach-to-designing-ui3/) | | **Maya** | Tabs. Click the current tab to collapse the pane, any tab to restore it. | Silent | Drag out to float, or dock | [Docs](https://help.autodesk.com/cloudhelp/ENU/MayaCRE-Basics/files/GUID-F4FCE554-1FA5-447A-8835-63EB43D2690B.htm) | | **3ds Max** | Thin labeled strip that opens on hover | The doc says "temporarily". Silent on reflow. | Command panel docks left or right only | [Docs](https://help.autodesk.com/cloudhelp/2024/ENU/3DSMax-Customizing/files/GUID-DBC08DD5-F581-486A-BD08-56A115CD32ED.htm) | | **DaVinci Resolve** 21.1 | Toolbar buttons and a Workspace menu | Silent | No general undock. Presets instead. | [Third-party guide](https://davinciresolveclub.com/davinci-resolve-workspace-layout-presets/) | | **Excalidraw** | A trigger button you place | Yes by default. Docking is opt-in, and undocked closes on outside click. | Dock toggle only | [Docs](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/children-components/sidebar) | | **tldraw** | Style panel floats top-right on desktop, and moves into a popover on mobile | Yes | No | [Docs](https://tldraw.dev/sdk-features/ui-components) | Miro and Photopea: I couldn't source anything useful, so I make no claim. Four patterns stand out: 1. **A persistent strip with labels or icons is the most common answer** in the tools built for long sessions. An overlay on top of that strip is a well-trodden combination. 2. **The move-to-side action is often not a drag on the whole panel.** VS Code uses a setting or context menu for the side bar. Godot uses a menu. JetBrains drags the rail icon. Only the classic docking systems drag the panel itself. 3. **Having several panels per side is rarer than it seems.** VS Code keeps Primary and Secondary on opposite sides and stacks views inside them. JetBrains supports a top and bottom split. Free arrangement belongs to Visual Studio, Unity and Unreal. 4. **Small tabs do exist in serious editors.** Blender's arrow is the good example, and it's in a 3D tool. Ant Design's [zero-width trigger](https://ant.design/components/layout) is the web equivalent, appearing when `collapsedWidth` is 0. ### Who has a tab you can drag along the edge? **No surveyed desktop or web editor documents one.** That's an absence in what I read, not proof that none exists. The examples I did find: | Example | Behavior | How it's regarded | | --- | --- | --- | | [Samsung Edge panels](https://www.samsung.com/us/support/answer/ANS00080551) | Handle drags up, down, or to the other side. There's a lock switch. Size and transparency are adjustable. | The closest match. The existence of a lock switch implies accidental moves happen (my inference). I found how-to guides for turning it off, but no quality data. | | [iOS AssistiveTouch](https://support.apple.com/en-am/111794) | Button drags to "any edge of the screen, where it stays" | Accessibility feature. Free-floating, not a panel handle. | | [PixieBrix extension](https://docs.pixiebrix.com/release-notes/release-notes-archive/release-1.7.31) | Experimental floating button with a drag handle and a hide button | Extensions inject into pages they don't own, so they need a way to dodge content. | | [Microsoft Edge sidebar](https://www.windowslatest.com/2024/09/30/you-can-remove-microsoft-edges-sidebar-if-you-dont-want-it-on-windows-11/amp/) | Always on / Auto hidden / Off. Not a draggable tab. | Third-party report from 2024. | Windows Copilot and Widgets: I found nothing that documents an edge-draggable tab, so I make no claim. My read (inference): this pattern exists where the UI floats over content it doesn't control, and so the user has to dodge the collision by hand. A library whose consumers control their own layout can solve the collision at authoring time. ## What do docking libraries tell us about the cost? Metrics are from GitHub, npm and Bundlephobia on 2026-11-04. Gzip is the Bundlephobia figure, shown only where I checked it. | Library | Stack, licence | Activity | Size | Touch | Collapse / overlay | | --- | --- | --- | --- | --- | --- | | [Dockview](https://github.com/dockview/dockview) | Vanilla, React, Vue, Angular. No Solid. [MIT core, proprietary enterprise](https://github.com/dockview/dockview/blob/HEAD/LICENCE.md). | 3.5k stars, v8.8.3 Oct 2026, ~868k weekly (`dockview-core`) | [90 KB](https://bundlephobia.com/api/size?package=dockview-core), zero deps | [Pointer backend, closed as done Sept 2026](https://github.com/dockview/dockview/issues/696). [An older mobile issue is still open](https://github.com/dockview/dockview/issues/930). | [Edge groups collapse to a 35px strip](https://dockview.dev/docs/core/groups/edgeGroups/). Auto-hide and [dock-to-edge](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoEdgeGroups.mdx) are enterprise. | | [FlexLayout](https://github.com/caplin/FlexLayout) | React, MIT | 1.4k stars, v0.11.1 Sept 2026, ~145k weekly | [53 KB](https://bundlephobia.com/api/size?package=flexlayout-react) | README claims iPad and Android. [Divider dragging reported flaky in 2024.](https://github.com/caplin/FlexLayout/discussions/432) | [Borders either split or overlay](https://caplin.github.io/FlexLayout/demos/v0.11/examples/borders/). The closest match to our modes. | | [Golden Layout](https://github.com/golden-layout/golden-layout) | Vanilla, MIT | 6.7k stars, last release Sept 2022, ~50k weekly | [30 KB](https://bundlephobia.com/api/size?package=golden-layout) | [Claimed](https://golden-layout.github.io/golden-layout/). [A touch-drag bug](https://github.com/golden-layout/golden-layout/issues/635) is closed, and I didn't confirm how it was fixed. | Not in what I read | | [rc-dock](https://github.com/ticlo/rc-dock) | React, Apache-2.0 | 815 stars, ~27k weekly | Not checked, six runtime deps | README doesn't claim it | Float, maximize | | [Dock Spawn TS](https://github.com/node-projects/dock-spawn-ts) | Vanilla, MIT | 148 stars, ~300 weekly, Oct 2026 | Not checked | README claims iPad, iPhone and Android | Pin-to-collapse tool panels | | [Lumino](https://github.com/jupyterlab/lumino) | Vanilla, used by JupyterLab | 764 stars, Oct 2026 | Not checked | [Touch request open since 2020](https://github.com/jupyterlab/lumino/issues/77) | Not reviewed | | [Theia](https://github.com/eclipse-theia/theia) | [Depends on Lumino](https://github.com/eclipse-theia/theia/blob/master/packages/core/package.json) | 21.7k stars, active | Full IDE framework | [Touch request open since 2018](https://github.com/eclipse-theia/theia/issues/3557) | Not reviewed | | [Dear ImGui docking](https://github.com/ocornut/imgui/wiki/Docking) | Native C++, MIT | Active | n/a | Not reviewed | Lives on a branch. The author plans a rewrite. | | [QDockWidget](https://doc.qt.io/qt-6/qdockwidget.html) | Qt | Maintained by Qt | n/a | Not reviewed | Closable, movable, floatable. Its page mentions no auto-hide. | | [Qt ADS](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System) | Qt add-on, LGPL | 2.5k stars, v5.1.1 Aug 2026 | n/a | Not reviewed | Auto-hide tabs in four sidebars, with drag to sidebar | | [AvalonDock](https://github.com/Dirkster99/AvalonDock) | WPF, MS-PL | 1.8k stars, v5.0.1 Oct 2026 | n/a | Not reviewed | Auto-hide manager, built-in sidebar | **The hard parts, as far as public evidence shows:** - **Touch.** It's where the mature libraries lag: Lumino's and Theia's requests have sat open for years, and Dockview only closed its drag request in September 2026. We've [already done this work for sections](./dnd.md), which is a real advantage. - **System gestures stealing drags.** Lumino has [an open bug](https://github.com/jupyterlab/lumino/issues/847) where a touch drag taken over by a system gesture ends in `pointercancel` and never releases. - **Keeping content alive while it moves.** Dockview's [rendering docs](https://dockview.dev/docs/core/panels/rendering/) spell out the trade-off: unmounting loses scroll position and measurements, keeping things mounted leaves work running, and re-parenting an iframe reloads it. Its tracker has fresh bugs in exactly this area ([moving into a collapsed edge group](https://github.com/dockview/dockview/issues/1738), [retained DOM](https://github.com/dockview/dockview/issues/1596)). - **The overlay and edge modes themselves.** Dockview's auto-hide and dock-to-edge sit behind its commercial licence, and [the public request for auto-hide](https://github.com/dockview/dockview/issues/1283) is still open. Qt's add-on exists largely to provide what `QDockWidget` doesn't (my inference). **WebGL.** I found no library documentation about a WebGL center specifically. That's a gap. We do have an architectural head start: the center stays put in all of (a) through (d), whereas in the general-purpose libraries the viewport would typically be one more movable panel (inference). Moving panels around a stationary canvas avoids most of this category of problem. **Should we adopt one instead of building?** No. Dockview's model is tabbed groups in a grid, and ours is sections in docks. Adopting it means replacing the model consumers already use and writing a Solid binding, plus paying for the feature most relevant here. This is my judgment, not a sourced finding. **Design systems point the same way:** - **[Material 3](https://m3.material.io/components/navigation-rail/guidelines):** the collapsed rail "should not be hidden", and compact windows "should always use a navigation bar" rather than a rail. The expanded rail's modal form "overlaps the body content" and suits "information dense layouts where space is limited". In immersive experiences it may be hidden entirely and opened from a menu icon, which supports our "no affordance" option. - **[shadcn](https://ui.shadcn.com/docs/components/sidebar):** `offcanvas`, `icon` and `none`, with a separate trigger and a Sheet on mobile. This is the closest web precedent for separating the panel from its toggle. - **[Fluent](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-drawer/library/README.md):** overlay is a per-case decision based on whether interacting with the background helps. - **[MUI](https://mui.com/material-ui/react-drawer/):** temporary, persistent and mini variants. - **[Carbon](https://carbondesignsystem.com/components/UI-shell-left-panel/usage/):** the left panel page describes a fixed panel and doesn't discuss overlay. ## What does the evidence say about each option? | Option | Solves the rest-state occlusion? | Keeps "no resize on open"? | Phone | Cost (my estimate) | Verdict | | --- | --- | --- | --- | --- | --- | | **(a)** Reserved strip | Fully | Yes | Poor: about 10% of a 390px screen for two strips | Small | Honest fallback | | **(b1)** Fixed tab | Mostly | Yes | Fine, if tap-only | Small | **Build now** | | **(b2)** Draggable tab | Mostly | Yes | Risky near the edge | Small to medium on top of b1 | Defer, probably never | | **"None"** + app toggle | Fully | Yes | Good | Small, shares b1's work | **Build now** | | **(c)** Rail | Fully | Yes, after one resize at mount | Replace with a bar | Medium | Wait for pull | | **(d1)** Side flip by setting | Unrelated | Unrelated | Fine | Small to medium | Wait for pull, cheap when it comes | | **(d2)** Drag to re-side | Unrelated | Unrelated | Hard | Large | Only after (c) | | **(d3)** Split tree, compass | Unrelated | Unrelated | Very hard | Very large | Avoid | ### (a) Reserved margin **For.** It's the mainstream arrangement in long-session tools: strip reserved, panel overlaid. Your objection is half right. Overlay's WebGL benefit survives, because the center resizes once at mount and never on open or collapse. Only the area benefit shrinks: at the normal tier a strip is [20px](../packages/solid-stage/src/theme/tokens.css), so two strips take about 2% of a 1920px window. Mouse users also keep a full-height target flush with the window edge, which Fitts's law treats as [effectively infinite in one direction](https://www.nngroup.com/articles/fitts-law/). **Against.** About 10% of a 390px phone. No information in the strip. A permanent reservation is exactly what overlay mode was added to avoid. **Fit.** Very easy: the overlay track goes from `0px` to `--stage-strip-width` while collapsed, and inset mode already does this. One catch: the track would need to stay at strip width whether the panel is open or collapsed, or the center resizes after all. ### (b) Small edge tab **For.** Blender and Ant are direct precedents. It removes the sliver over the toolbars and most of the area loss. **Against.** - **It still occludes.** Less area, but a tab twice the bar's width reaches further into the stage. At the normal tier that's 40px deep. I'd make it narrower for mouse (see the sizes below). A tab placed at the vertical center is likely to avoid `topSub` and `bottomSub` (inference, and worth checking in real consumers). - **Discoverability.** NN/g's [study of hidden navigation](https://www.nngroup.com/articles/hamburger-menus/) (2016, 179 participants) found discoverability dropped more than 20% and desktop tasks took at least 39% longer. That's about content sites, so it applies only loosely to a power tool whose users learn the layout quickly. But it's a reason not to make `none` the default. - **Gaps ruin edge targets.** An Unreal user [calls a small gap between the sidebar and the screen edge a "pixel hunt"](https://forums.unrealengine.com/t/engines-ui-docking-to-sidebar/1785192). The tab must be flush with the window edge. **Target sizes.** - Apple asks for [a 44x44pt hit region](https://developer.apple.com/design/human-interface-guidelines/buttons). - Material suggests [48x48dp, noting the target can exceed the visual](https://m3.material.io/foundations/designing/structure). - WCAG's [minimum is 24x24 CSS px, with a spacing exception](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html). So a modest visible tab can carry a larger hit region on `pointer: coarse`. Our strip at the normal and small tiers is under 24px wide, so it depends on that spacing exception (my reading, not an audit). **Why not the drag?** - **Precedent is weak**, as shown above. - **A tap and a drag on a tiny target have to be told apart.** We have that threshold logic in the edge variant, but on touch the two are easier to confuse. - **It adds state:** a persisted position, clamping on resize, collision with other UI. It also needs a non-drag way to reposition, since [WCAG 2.5.7](https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements.html) asks for a single-pointer alternative to dragging. - **It starts in the worst place on an iPhone.** See the next section. If collisions turn up, a `--stage-panel-tab-offset`-style setting fixes them at authoring time, and it's the same value a later drag would write. So we lose nothing by waiting. ### Touch and edge gestures (applies to anything on the edge) - **Don't add swipe-to-open.** WebKit [closed the request to let pages handle edge swipes first as WONTFIX](https://bugs.webkit.org/show_bug.cgi?id=149015), on the grounds that back-swipe should be consistent. Apple's guidance is to [avoid conflicting with gestures that access system UI](https://developer.apple.com/design/human-interface-guidelines/gestures). MUI [turns off swipe discovery on iOS](https://mui.com/material-ui/react-drawer/) for this reason. Android needs [explicit exclusion rects](https://developer.android.com/develop/ui/views/touch-and-input/gestures/gesturenav), which a web page can't set (my inference). - **A workaround exists, but don't lean on it.** A [2020 post](https://pqina.nl/blog/blocking-navigation-gestures-on-ios-13-4/) blocks navigation gestures with `preventDefault` on `touchstart` within 20px of the edge. I didn't verify it on current iOS, and it would need testing on the real iPhone. - **Tap is safe. Vertical drag near the edge is unverified.** A drag starting in that zone may be cancelled by the system, as in the [Lumino bug](https://github.com/jupyterlab/lumino/issues/847). This is an inference to test before ever shipping (b2). - **Edges don't help on touch.** NN/g reports that the screen-edge advantage ["offers no advantage for touchscreens"](https://www.nngroup.com/articles/fitts-law/) and edge targets may even be slower. ### (c) Rail **For.** The most established answer: VS Code, JetBrains, Photoshop's icon dock, and Material's formal component. It's informative, since it shows what's available. Combined with overlay, the center never resizes when panels open, which is a clean pairing. The [June report](./editor-side-navigation-patterns.md) already worked out the router model and recommends labels over icon-only. **Against.** - It costs a permanent 44px or more per side once buttons are big enough. That's about 11% of a phone per side, and Material says [not to use a rail on compact windows](https://m3.material.io/components/navigation-rail/guidelines) at all. So we'd need a second form for phones, which is real extra design. - One-panel apps get a rail with one icon, which is a poor trade against a tab. - It needs an API for views that doesn't exist, and today's consumers author `leftPanel` as plain JSX. **A correction to the June report.** It cited [vscode#260437](https://github.com/microsoft/vscode/issues/260437) as pressure to keep rail icons visible. That issue was closed as not planned in October 2025 by a bot, for lack of votes. It's still a fair statement of the request, but weaker evidence than that report implied. Material's "should not be hidden" is the better citation. **"Multiple panels per side" is two features.** One at a time via the router is what VS Code does and is cheap. Two visible at once with a divider is what JetBrains does and needs a splitter and more state. Today's stacked `Section`s and accordion docks already cover much of the need for the second one (my judgment). ### (d) Dockable to either side Sections can [already move between docks with an insertion line](./dnd.md), so users can already rearrange the content. What (d) adds is smaller than it sounds: moving the whole panel at once. The [existing limit](./dnd.md#whats-not-built) is that "dragging the static side panels themselves" isn't built. - **(d1) Side flip by setting.** This is VS Code's `workbench.sideBar.location`. It needs no drag, no indicator and no new interaction. The work is that chevrons, cover variables, persist keys and overlay positioning must follow a logical side. - **(d2) Drag to re-side.** The cheaper form is [JetBrains' icon drag between bars](https://www.jetbrains.com/help/idea/manipulating-the-tool-windows.html), which depends on (c). Rails give a small set of drop targets, and the existing insertion line can serve as the indicator. Panel-header dragging without a rail has no drop target when the other side is empty, so we'd need Unity-style or dock-to-edge-style zones that appear during a drag, as [Dockview's enterprise feature](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoEdgeGroups.mdx) does. - **(d3) Split tree with a guide diamond.** The [diamond](https://learn.microsoft.com/en-us/visualstudio/ide/customizing-window-layouts-in-visual-studio) exists because a drop could mean any of many positions in a tree. We have no tree. Without one, a compass solves a problem we don't have (inference). **Failure modes to expect from (d2) and up:** - **Accidental rearrangement is real.** 3ds Max [tells users who float the panel by accident to turn on Lock UI Layout](https://help.autodesk.com/cloudhelp/2026/ENU/3DSMax-Customizing/files/GUID-E625E116-6070-4A02-9A31-672BA6A0A954.htm). We have `locked` for sections, and it would have to cover panels too. - **Empty sides.** What does a side with no panels look like, and how do you drop onto it? - **Persistence.** Saved layouts need a version bump and migration. Consumers' HUDs anchored to `--stage-panel-cover-left` may now be under the wrong panel. - **Remounts.** Sections [remount when they change docks](./dnd.md), so a whole-panel move remounts every section in it, including any heavy ones (inference from the `render` thunk rule). - **Nested stages.** Embedded stages multiply the possible targets. - **Phones.** On a phone there's barely a "side" to move to, so this feature mostly doesn't apply there. ### Is overlay itself a good long-term default? A caution Figma's experience is the strongest evidence here. It shipped floating panels over the canvas in its UI3 beta, then [went back to fixed panels](https://www.figma.com/blog/our-approach-to-designing-ui3/): they cramped the canvas, content "peeked" distractingly from behind them, and "the nail in the coffin was learning that they slowed people down". Community complaints [included wasted space and overlap](https://forum.figma.com/suggest-a-feature-11/launched-fixed-panels-are-back-23789). Floating did survive in Minimize UI and in FigJam. So: **keep `inset` as the default, as it is today, and treat `overlay` as the mode for canvas-first or low-edit sessions.** A dense property editor that's always open may be better off inset, and that's worth saying in the docs. **Auto-dismiss is divisive, so don't add it by default.** VS Code users [want overlay with auto-hide](https://github.com/microsoft/vscode/issues/3742), while Unreal users [say auto-hide "messes me up so often"](https://forums.unrealengine.com/t/feature-request-disable-content-browser-auto-hide/1238959) and call Dock in Layout a workaround. Today's "tapping outside doesn't close it" is the safe choice. One caveat is that WCAG's [focus-not-obscured guidance](https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html) treats persistent non-modal overlays as a risk for covering focused items, so keyboard users need a clear way to dismiss the panel. I didn't audit our current behavior against it. ## What should we do, and in what order? ### Do now: collapsed affordance for overlay panels Removes the immediate complaint. No consumer change required, because the default stays as it is. ```ts // Sketch, not final naming. Applies to the collapsed state of an overlay panel. leftCollapsedAffordance?: 'strip' | 'tab' | 'none'; // default 'strip' rightCollapsedAffordance?: 'strip' | 'tab' | 'none'; ``` - **`strip`:** today's behavior. - **`tab`:** a small button flush with the window edge. Vertically centered by default, with a CSS variable for its offset. Visibly narrow, with a 44px-minimum hit region on `pointer: coarse`. Tap or click only, no hover and no swipe. - **`none`:** nothing on screen. The app toggles through the existing controlled props (`leftCollapsed`, `onLeftToggle`) from a button in `topToolbars`, which the panel [never covers](./layout.md). Docs should say plainly that the app must provide a way back. - **Cover variables:** `--stage-panel-cover-*` should read `0px` for `tab` and `none` while collapsed, so HUDs get the space back. Deriving that value from one accessor is cleaner than a parallel calculation. - **Don't bind a keyboard shortcut in the library.** VS Code and shadcn use Ctrl/Cmd+B, but in a library that's the app's decision, and the controlled props already make it easy. - **Test on the real iPhone**, in both portrait and landscape, with the tab near the safe areas. - **Keep `strip` for mouse-first apps.** Fitts's law favors it, and it's not wrong in inset mode, where it already takes its own column. The width clamp of `[140px, 40% of the stage]` gives about 156px on a 390px phone, which looks tight for dense settings. tldraw uses a popover on mobile and shadcn a Sheet. That's a separate question worth raising, and I'd wait for a real phone complaint before acting on it. ### Next, only if a real need appears | Step | Build it when | What it reuses | | --- | --- | --- | | **Tab offset per app** | Comes with the first step | CSS variable | | **Reserved strip (a)** | Two consumers say the tab still collides | Inset mode's track logic | | **Side flip (d1)** | A consumer or user group wants panels on the opposite side | Existing panels, a logical-side concept | | **Rail (c)** | A consumer has 3+ mutually exclusive views on one side, and `Section` collapse and accordions aren't enough. Per `feature-ideas.md`, a second consumer should want it. | June report's router shape, `createPersistedToggle`, `TabMenu` patterns | | **Icon drag between rails (d2)** | After (c) ships, and users ask to rearrange beyond moving sections | Pointer drag, insertion line, `dockHitTest`, the `locked` flag | **How these depend on each other:** ```mermaid flowchart LR A[Affordance: tab / none] --> B[Offset variable] B -.->|only if needed| C[Draggable tab] A -.->|independent| D[Reserved strip] E[Rail] --> F[Drag icons between rails] G[Side flip] -.->|independent of the rail| E F -.->|very unlikely| H[Split tree and compass] ``` So yes, **(c) and (d) are separable**, but not in the obvious direction. (d1) needs nothing. (d2) is far cheaper after (c). (c) needs no part of (d). ### What consumers do today At the local checkouts I read (dsts-viewer `bb560b7`, osrs-engine-study `1b28621`, world-sim-assets `e37c515`), only the solid-stage playground and tests set `leftPanelMode` or `rightPanelMode`. dsts-viewer uses `edge` toggles. osrs-engine-study uses `DockZone`s with the ids `left` and `right` only. That was a targeted search for these props and dock ids, not a read of each app, so it shows no sign of demand for more docks rather than proving there's none. These checkouts may lag behind work in progress, so check with the consumers before relying on this. I'd take it as a reason to build the small step, and as a clear signal to hold the large ones. ### What not to do - **Don't wrap Dockview or similar.** Wrong model, and the relevant features are paid. - **Don't build the split tree or the guide diamond.** The repo's rule against hypothetical needs applies directly, and sections and floating panels already cover flexible arrangement. - **Don't add swipe-to-open**, for the reasons above. - **Don't make the panel open on hover by default.** 3ds Max and browser sidebars do it, and it doesn't exist on touch, which makes it a second code path. [Users do ask for it](https://forums.unrealengine.com/t/engines-ui-docking-to-sidebar/1785192), so it could become an opt-in later. - **Don't default to `none`.** A hidden panel with no affordance is the discoverability trap. - **Don't add a phone rail.** Follow Material: use a bar or toolbar buttons on compact widths. ## Sources **Local:** [`docs/editor-side-navigation-patterns.md`](./editor-side-navigation-patterns.md), [`docs/layout.md`](./layout.md), [`docs/dnd.md`](./dnd.md), `docs/architecture.md`, `docs/feature-ideas.md`, `packages/solid-stage/src/theme/tokens.css`, and the consumer repos named above. **Editors (vendor docs):** - [VS Code: Custom Layout](https://code.visualstudio.com/docs/configure/custom-layout), [User Interface](https://code.visualstudio.com/docs/getstarted/userinterface) - [JetBrains: Tool window view modes](https://www.jetbrains.com/help/idea/viewing-modes.html), [Tool windows](https://www.jetbrains.com/help/idea/tool-windows.html), [Arrange tool windows](https://www.jetbrains.com/help/idea/manipulating-the-tool-windows.html), [New UI](https://www.jetbrains.com/help/idea/new-ui.html) - [Visual Studio: Customize window layouts](https://learn.microsoft.com/en-us/visualstudio/ide/customizing-window-layouts-in-visual-studio) - [Blender: Regions](https://docs.blender.org/manual/en/latest/interface/window_system/regions.html), [Interface preferences](https://docs.blender.org/manual/en/latest/editors/preferences/interface.html), [3D Viewport Sidebar](https://docs.blender.org/manual/en/latest/editors/3dview/sidebar.html) - [Unity: Customize your workspace](https://docs.unity.com/en-us/engine/current/manual/extending-the-editor/customizing-your-workspace), [Overlays](https://docs.unity.com/en-us/engine/current/manual/working-with-scenes/scenes-manage-gameobjects/overlays), [Position an overlay](https://docs.unity.com/en-us/engine/6000.6/manual/working-with-scenes/scenes-manage-gameobjects/overlays/position-and-display/position-overlay) - [Unreal: Content Browser](https://dev.epicgames.com/documentation/en-us/unreal-engine/content-browser-in-unreal-engine), [Editor Interface](https://dev.epicgames.com/documentation/en-us/unreal-engine/unreal-editor-interface) - [Godot: Customizing the interface](https://docs.godotengine.org/en/stable/tutorials/editor/customizing_editor.html) - [Photoshop: Expand or collapse panel icons](https://helpx.adobe.com/photoshop/desktop/get-started/learn-the-basics/collapse-expand-icons.html), [InCopy: Workspace basics](https://helpx.adobe.com/hk_en/incopy/desktop/get-started/settings-and-preferences/workspace-basics.html) - [Figma: Our approach to designing UI3](https://www.figma.com/blog/our-approach-to-designing-ui3/) - [Maya: Interface overview](https://help.autodesk.com/cloudhelp/ENU/MayaCRE-Basics/files/GUID-F4FCE554-1FA5-447A-8835-63EB43D2690B.htm) - [3ds Max: Customize Display menu](https://help.autodesk.com/cloudhelp/2024/ENU/3DSMax-Customizing/files/GUID-DBC08DD5-F581-486A-BD08-56A115CD32ED.htm), [Useful Customization Techniques](https://help.autodesk.com/cloudhelp/2026/ENU/3DSMax-Customizing/files/GUID-E625E116-6070-4A02-9A31-672BA6A0A954.htm) - [Excalidraw: Sidebar](https://docs.excalidraw.com/docs/@excalidraw/excalidraw/api/children-components/sidebar) - [tldraw: UI components](https://tldraw.dev/sdk-features/ui-components) **Editors (secondary and community):** - [DaVinci Resolve workspace presets, third-party guide](https://davinciresolveclub.com/davinci-resolve-workspace-layout-presets/) - VS Code issues [#3742](https://github.com/microsoft/vscode/issues/3742), [#248900](https://github.com/microsoft/vscode/issues/248900), [#178375](https://github.com/microsoft/vscode/issues/178375), [#193267](https://github.com/microsoft/vscode/issues/193267), [#260437](https://github.com/microsoft/vscode/issues/260437) - Unreal forums: [Docking to Sidebar](https://forums.unrealengine.com/t/engines-ui-docking-to-sidebar/1785192), [Disable Content Browser Auto Hide](https://forums.unrealengine.com/t/feature-request-disable-content-browser-auto-hide/1238959), [Keep Content Tray Open](https://forums.unrealengine.com/t/keep-content-tray-open/267048) - Figma forum: [Independent panel collapsing](https://forum.figma.com/suggest-a-feature-11/bring-back-independent-left-right-panel-collapsing-as-in-ui2-42703), [Fixed panels are back](https://forum.figma.com/suggest-a-feature-11/launched-fixed-panels-are-back-23789) **Edge handles:** - [Samsung: Edge panels](https://www.samsung.com/us/support/answer/ANS00080551) - [Apple: AssistiveTouch](https://support.apple.com/en-am/111794) - [PixieBrix release notes](https://docs.pixiebrix.com/release-notes/release-notes-archive/release-1.7.31) - [Windows Latest: Edge sidebar](https://www.windowslatest.com/2024/09/30/you-can-remove-microsoft-edges-sidebar-if-you-dont-want-it-on-windows-11/amp/) **Docking libraries:** - Dockview: [site](https://www.dockview.dev/), [repo](https://github.com/dockview/dockview), [licence](https://github.com/dockview/dockview/blob/HEAD/LICENCE.md), [rendering](https://dockview.dev/docs/core/panels/rendering/), [edge groups](https://dockview.dev/docs/core/groups/edgeGroups/), [auto-hide](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoHideEdgeGroups.mdx), [dock to edge](https://github.com/dockview/dockview/blob/HEAD/packages/docs/docs/core/groups/autoEdgeGroups.mdx), issues [#696](https://github.com/dockview/dockview/issues/696), [#930](https://github.com/dockview/dockview/issues/930), [#1283](https://github.com/dockview/dockview/issues/1283), [#1596](https://github.com/dockview/dockview/issues/1596), [#1738](https://github.com/dockview/dockview/issues/1738) - FlexLayout: [repo](https://github.com/caplin/FlexLayout), [borders demo](https://caplin.github.io/FlexLayout/demos/v0.11/examples/borders/), [#432](https://github.com/caplin/FlexLayout/discussions/432) - Golden Layout: [repo](https://github.com/golden-layout/golden-layout), [site](https://golden-layout.github.io/golden-layout/), [#635](https://github.com/golden-layout/golden-layout/issues/635) - [rc-dock](https://github.com/ticlo/rc-dock), [Dock Spawn TS](https://github.com/node-projects/dock-spawn-ts) - Lumino: [repo](https://github.com/jupyterlab/lumino), [#77](https://github.com/jupyterlab/lumino/issues/77), [#847](https://github.com/jupyterlab/lumino/issues/847) - Theia: [repo](https://github.com/eclipse-theia/theia), [`@theia/core` package.json](https://github.com/eclipse-theia/theia/blob/master/packages/core/package.json), [#3557](https://github.com/eclipse-theia/theia/issues/3557) - [Dear ImGui: Docking](https://github.com/ocornut/imgui/wiki/Docking), [QDockWidget](https://doc.qt.io/qt-6/qdockwidget.html), [Qt ADS](https://github.com/githubuser0xFFFF/Qt-Advanced-Docking-System), [AvalonDock](https://github.com/Dirkster99/AvalonDock) - Sizes: Bundlephobia for [dockview-core](https://bundlephobia.com/api/size?package=dockview-core), [flexlayout-react](https://bundlephobia.com/api/size?package=flexlayout-react), [golden-layout](https://bundlephobia.com/api/size?package=golden-layout). Weekly downloads came from the npm registry API. **Design systems:** - [Material 3: Navigation rail guidelines](https://m3.material.io/components/navigation-rail/guidelines), [Accessibility designing](https://m3.material.io/foundations/designing/structure) - [MUI: Drawer](https://mui.com/material-ui/react-drawer/) - [shadcn: Sidebar](https://ui.shadcn.com/docs/components/sidebar) - [Ant Design: Layout](https://ant.design/components/layout) - [Fluent: react-drawer README](https://github.com/microsoft/fluentui/blob/master/packages/react-components/react-drawer/library/README.md) - [Carbon: UI shell left panel](https://carbondesignsystem.com/components/UI-shell-left-panel/usage/) **Usability, accessibility and platform:** - NN/g: [Fitts's Law](https://www.nngroup.com/articles/fitts-law/), [Hamburger Menus and Hidden Navigation](https://www.nngroup.com/articles/hamburger-menus/) - WCAG 2.2: [Target Size (Minimum)](https://www.w3.org/WAI/WCAG22/Understanding/target-size-minimum.html), [Dragging Movements](https://www.w3.org/WAI/WCAG22/Understanding/dragging-movements.html), [Focus Not Obscured](https://www.w3.org/WAI/WCAG22/Understanding/focus-not-obscured-minimum.html) - Apple HIG: [Buttons](https://developer.apple.com/design/human-interface-guidelines/buttons), [Gestures](https://developer.apple.com/design/human-interface-guidelines/gestures) - [WebKit bug 149015](https://bugs.webkit.org/show_bug.cgi?id=149015) - [PQINA: Blocking navigation gestures on iOS](https://pqina.nl/blog/blocking-navigation-gestures-on-ios-13-4/) - [Android: Gesture navigation](https://developer.android.com/develop/ui/views/touch-and-input/gestures/gesturenav) **Fallbacks.** `docs.blender.org` and `helpx.adobe.com` returned 403 to the default fetcher and were read through a browser-impersonating client. `m3.material.io`, Apple's HIG and the FlexLayout demo are JavaScript-rendered and were read through a headless browser. GitHub content came from the `gh` API, so GitHub links in this report are the web equivalents of what I read. ## Further research **Open questions** - **Does a flush tab behave on a real iPhone?** Test tap reliability near the safe areas, and whether a vertical drag from the edge zone gets cancelled. This decides whether (b2) is even viable. - **Where do consumers actually put HUDs?** My vertical-center default is a guess until it's checked against dsts-viewer and osrs-engine-study layouts. - **Should an overlay panel become a modal sheet on phones?** tldraw and shadcn both change form on mobile, and the current width clamp looks tight. This is outside the question asked, but it's adjacent. - **Does anyone plan to use overlay mode?** No consumer does at the commits I checked, so it's worth confirming before investing further. **Weakly sourced claims** - **Unreal's sidebar tabs** rest on forum threads and not on Epic docs. Content Drawer behavior is from Epic docs. - **Figma's Minimize UI collapsing both sides** comes from user posts. The Figma blog describes the feature but not that detail. - **DaVinci Resolve** comes from a third-party guide citing the 21.1 manual. Mirror pages of the manual that I tried returned 404. - **Edge's "Auto hidden" mode** comes from one 2024 tech-news article. - **The iOS `preventDefault` workaround** is from 2020, and I couldn't confirm it on current iOS. - **The NN/g hidden-navigation numbers** are from content sites in 2016. Applying them to expert tools is my extrapolation. - **Cost estimates** throughout are my judgment from reading our docs and file sizes. They aren't measured. **Inaccessible or empty** - [Lean Library's floating button help](https://support.leanlibrary.com/hc/en-gb/articles/5034655597727-Floating-Button-What-is-it-and-how-to-use-it): redirects to a sign-in page in a headless browser. Search snippets suggested a corner-position setting, which I left out as unverified. - [Orion's sidebar-hover thread](https://orionfeedback.org/d/684-sidebar-openclose-on-hover/103): the page failed to load usable content, so I didn't use it for Arc or Zen hover behavior. - [Samsung community thread on opening Edge panels with a case](https://community.samsung.com/uk/conversations/galaxy-s22-series/opening-the-edge-panel-on-a-flat-screen-with-case-is-difficult/eu_8979537): only the title was readable. - [SAP's mirror of Material drawer guidance](https://www.sap.com/design-system/fiori-design-android/v26-4/components/m3-standard-components/navigation-drawer/usage): 404. As a result I didn't verify a search snippet claiming Material 3 Expressive deprecates the navigation drawer. - [Photopea's learning index](https://www.photopea.com/learn/): nothing on side panels. Miro: nothing found. Both are left out of the survey. **Gaps in the source material** - **I found no controlled study** comparing edge tabs, rails and strips for property-heavy editors. Everything here is vendor practice, user complaints and adjacent research. - **I found no quality data on draggable edge handles.** Samsung's feature has settings docs and how-to guides, not usability findings. - **I found no docking library documentation about a WebGL center**, including the effect of moving a `` between parents. It doesn't affect the recommendation, since the center stays still, but it would matter if the viewport ever became a movable panel. - **Docs often don't say whether a panel reflows the content.** JetBrains' Dock Unpinned, Photoshop's expanded icons and 3ds Max's hover strip all fall here. Hands-on testing would settle it. - **Dockview's public auto-hide request remains open** even though the enterprise docs describe the feature. I didn't determine whether anything is planned for the MIT core.