Ruben Khachaturov99 downloadsKeep your document open while your sidebars change. Switch between a stack of panels and a full-height chat with one click. Save independent layouts for the left and right sidebar.
A sidebar holds one arrangement at a time. You can split it by hand, but there is only ever one, and getting another means taking that one apart.
This keeps as many as you name. An AI chat at full height for one task. The same sidebar split three ways for another - backlinks, outline, tags, at the heights you set. A third with two panels. Each arrangement becomes a button in the sidebar's own header, and switching is one click.
Switching moves the panels that are already open instead of rebuilding them, so each one keeps what it holds - a scroll position, a selection, text typed into a panel but not yet sent.
Each sidebar has its own layouts and its own active one, so switching on one side leaves the other side and its live views alone.

Source: mrkhachaturov/obsidian-sidebar-layouts.
Not in Obsidian's community plugin browser yet: a plugin is submitted there after its first release, and appears once that submission has been reviewed. Until then, either route below installs it.
mrkhachaturov/obsidian-sidebar-layouts to it. It installs the latest release and follows the
ones after it.main.js, manifest.json and styles.css from the
latest release, put
them in <vault>/.obsidian/plugins/sidebar-layouts/, then enable the plugin under Settings →
Community plugins.Requires Obsidian 1.13.0 or later, on desktop. The plugin rearranges the panes a sidebar is built from, and mobile does not have that sidebar.
The whole arrangement, not a single panel:
The upper group stays in place, which is what lets a live panel survive the switch. Groups below it may be rebuilt when their arrangement changes, and existing tabs are moved into them rather than closed. The note you are reading is never touched.
A button belongs to one sidebar and does one of two things: apply a layout, or run any command in your vault. Save current layout and Add command create them; Edit buttons renames and reorders them, by dragging or with the keyboard.

The last two apply to both sidebars; the rest belong to one button. Each button has a page of its own, which is also where a layout is applied and where the two options below live.

A layout has the arrangement you saved on purpose, and the changes you made to it afterwards.
Move a divider or reveal another panel while a layout is active, and the change is remembered as that layout's working arrangement once the sidebar settles. Switch away and back, and it is still there. What you saved stays untouched until you say otherwise:
Both are on the layout's page in the settings and in the right-click menu of its button. A layout carrying working changes is marked in the settings list.
Opening a note on top of a layout is not a change to it, and neither is the collapse below.
Turn this on for a layout, and while a note is revealed at the top of the sidebar, the panels below are parked so the note has the whole height. Returning to a panel, or turning the option off, brings them back at their stored heights.
Every layout can register a command of its own, named after the layout - the Add to the command palette toggle on its page. Turning it off removes the command and keeps the button.
Because a layout is an ordinary command, anything that runs commands can switch layouts: a hotkey, a command launcher, or a rule that reacts to what you open. Triggers is the last of those — it runs commands when you open a note, a Base or a canvas that matches a rule you wrote, so the sidebar can rebuild itself around what is in front of you.
| Command ID | Command name |
|---|---|
sidebar-layouts:apply-right |
Sidebar Layouts: Switch right sidebar layout |
sidebar-layouts:apply-left |
Sidebar Layouts: Switch left sidebar layout |
sidebar-layouts:save-as-new-right |
Sidebar Layouts: New layout from the right sidebar |
sidebar-layouts:save-as-new-left |
Sidebar Layouts: New layout from the left sidebar |
sidebar-layouts:apply-<layout id> |
Sidebar Layouts: the layout's own name |
The two switch commands open a picker of the layouts saved for that sidebar.
The interface follows the language selected in Obsidian - the settings, the dialogs, command names, tooltips and the plugin's own messages are all translated, and English stands in wherever a translation has not caught up. More languages are added over time: one is a file of strings and needs no other change to the plugin.
Names you type, and labels that come from Obsidian or another plugin, are left as they are.
Other plugins can read and apply layouts through app.plugins.plugins['sidebar-layouts'].api,
after checking that the plugin is enabled.
| Member | Returns |
|---|---|
version |
The API version, currently 1 |
list(side?) |
Saved layouts - one sidebar's, or all of them with their side |
governing(side) |
The id of the layout active in that sidebar |
apply(id) |
Applies a layout, on the side it belongs to, and resolves when it is done |
capture(side) |
That sidebar's arrangement as it looks now |
The side is left or right. Layouts are returned as copies, so changing them does not change what
is stored.
Every change passes the same gates before it lands: biome,
ESLint with the official
Obsidian plugin,
TypeScript with strict and then some,
Vitest with coverage, knip for dead code, and a check
that the CSS classes the plugin ships and the ones its source uses are the same set.
mise run check is the whole set, and it runs again before every push. CI runs it on pull requests
and on pushes to main, alongside CodeQL with security-extended,
a dependency review that blocks a pull request adding a high-severity advisory, and the
OpenSSF Scorecard. Released files carry build provenance, so an
installed copy can be traced back to the run that produced it.
How a release is cut is written in .github/RELEASING.md, and what changed in each one is in CHANGELOG.md.
Automated tests cannot establish how Obsidian lays panels out on a screen, or whether an event fires in a real vault, so an interface change is also looked at in a running vault before it ships.
No network requests of any kind. No telemetry, no update checks, no downloads.
The plugin never reads or writes your notes. It arranges panels, and keeps its own layouts in
data.json inside its plugin folder.
mise install && mise run bootstrap # tools, then dependencies
mise run check # every gate
VAULT=/path/to/vault mise run plugin:install
Tool versions live in mise.toml; npm versions and the resolved dependency tree live in
package.json and package-lock.json. bootstrap runs npm ci - run it again after changing
branches when the lockfile changes. Tasks use project-local binaries and never download a missing
compiler or test runner implicitly.
| Task | What it checks or produces |
|---|---|
mise run lint |
Formatting and generic lint through flint |
mise run lint:code |
Obsidian rules and type-aware ESLint |
mise run test:types |
TypeScript for source and test fixtures |
mise run test:unit |
Unit and DOM tests |
mise run test:coverage |
Tests and coverage for all source modules |
mise run test:dead |
Unreachable files, unused exports, unresolved imports |
mise run test:styles |
Agreement between plugin CSS classes and source |
mise run check |
All gates, including the production build |
mise run build |
Typecheck and bundle into main.js |
mise run dev |
Rebuild the development bundle on source changes |
mise run fmt |
Apply the fixes supported by flint |
plugin:install builds first, then copies main.js, manifest.json and styles.css into that
vault's plugin folder. Settings already in the vault's data.json are left alone. Git hooks install
through mise: pre-commit runs hygiene and formatting, commit-msg checks conventional commits, and
pre-push runs mise run check.
MIT. See LICENSE.