Created
December 1, 2025 05:56
-
-
Save grahamhelton/8f667011f49fae7748340d5344e40d6f to your computer and use it in GitHub Desktop.
Obsidian plugin to open panes in the right tab
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "id": "open-in-right-pane", | |
| "name": "Open in Right Pane", | |
| "version": "1.0.0", | |
| "minAppVersion": "1.0.0", | |
| "description": "Links clicked in the left pane always open as a new tab in the right pane.", | |
| "author": "Graham Helton", | |
| "isDesktopOnly": false | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| const { Plugin } = require('obsidian'); | |
| module.exports = class OpenInRightPanePlugin extends Plugin { | |
| async onload() { | |
| // Use capture phase to intercept before Obsidian's handler | |
| this.handleClick = this.handleClick.bind(this); | |
| document.addEventListener('click', this.handleClick, true); | |
| } | |
| onunload() { | |
| document.removeEventListener('click', this.handleClick, true); | |
| } | |
| handleClick(evt) { | |
| const target = evt.target; | |
| // Check if clicked element is an internal link | |
| const link = target.closest('a.internal-link'); | |
| if (!link) return; | |
| // Get the source leaf (where the click happened) | |
| const sourceLeaf = this.app.workspace.activeLeaf; | |
| if (!sourceLeaf) return; | |
| // Get the root split | |
| const rootSplit = this.app.workspace.rootSplit; | |
| if (!rootSplit || !rootSplit.children || rootSplit.children.length < 2) return; | |
| // Check if source is in the left pane (first child of root split) | |
| const leftSplit = rootSplit.children[0]; | |
| const rightSplit = rootSplit.children[1]; | |
| let isInLeftPane = false; | |
| let current = sourceLeaf; | |
| while (current) { | |
| if (current === leftSplit) { | |
| isInLeftPane = true; | |
| break; | |
| } | |
| current = current.parent; | |
| } | |
| if (!isInLeftPane) return; | |
| // Get link target | |
| const linkPath = link.getAttribute('href'); | |
| const file = this.app.metadataCache.getFirstLinkpathDest(linkPath, ''); | |
| if (!file) return; | |
| // Stop the event from reaching Obsidian's handler | |
| evt.preventDefault(); | |
| evt.stopPropagation(); | |
| evt.stopImmediatePropagation(); | |
| // Find a leaf in the right pane or create one | |
| let targetLeaf = null; | |
| const findLeafInSplit = (split) => { | |
| if (split.type === 'leaf') return split; | |
| if (split.children) { | |
| for (const child of split.children) { | |
| const found = findLeafInSplit(child); | |
| if (found) return found; | |
| } | |
| } | |
| return null; | |
| }; | |
| const existingLeaf = findLeafInSplit(rightSplit); | |
| if (existingLeaf) { | |
| // Create new tab in the right pane's tab group | |
| targetLeaf = this.app.workspace.createLeafInParent(existingLeaf.parent, -1); | |
| } else { | |
| targetLeaf = this.app.workspace.getLeaf('split', 'vertical'); | |
| } | |
| // Open file in target leaf | |
| targetLeaf.openFile(file); | |
| } | |
| }; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment