[Feature Request] Add "Auto-focus tab when content matches" toggle for separate sidebar tabs (Mobile drawer ergonomics)
Problem / Motivation
When using Virtual Content with renderLocation: "sidebar" and showInSeparateTab: true", the content is rendered into a dedicated sidebar tab (e.g., virtual-content-separate-view-X).
This works great, but introduces a UX friction point—especially on Obsidian Mobile:
- Obsidian's right sidebar / mobile drawer remembers the last active tab (e.g. Outline, Backlinks, Tags, or another plugin view).
- When a user opens a note that triggers a specific Virtual Content sidebar rule (such as a Dashboard, Project note, or CRM entity) and swipes left to open the drawer expecting that tab, Obsidian displays whichever unrelated tab was active previously.
- The user is then forced to perform a second, precise tap on the small tab icon in the mobile header.
Proposed Solution
Add an optional toggle under sidebar rule settings:
- "Auto-focus tab when content matches"
- When enabled, whenever the active note matches the rule and generates content, the plugin automatically ensures that this tab is selected as the active tab in its parent sidebar container.
Key UX Detail: Calling leaf.parent.selectTab(leaf) switches the active tab inside the mobile drawer / sidebar without calling revealLeaf(). This means the drawer does not jump open or disrupt the user while reading or typing—it simply guarantees that when the user does swipe the drawer open, the correct tab is already active and waiting.
Implementation Details & Code
Here is the implementation that can be added to the plugin:
1. Extend the Rule interface & defaults
In rule type definitions:
export interface Rule {
// ... existing fields ...
showInSeparateTab?: boolean;
sidebarTabName?: string;
autoFocusSidebarTab?: boolean; // NEW: Auto-select tab when content matches
}
In default settings / rule sanitization:
autoFocusSidebarTab: typeof rule.autoFocusSidebarTab === "boolean" ? rule.autoFocusSidebarTab : false,
2. Add Setting Toggle in RuleModal
Inside renderLocationSpecificControls(containerEl: HTMLElement):
if (this.workingRule.renderLocation === "sidebar") {
new Setting(containerEl)
.setName("Show in separate tab")
.setDesc("If enabled, this content appears in its own sidebar tab.")
.addToggle(toggle => toggle
.setValue(this.workingRule.showInSeparateTab ?? false)
.onChange(value => {
this.workingRule.showInSeparateTab = value;
this.render();
})
);
if (this.workingRule.showInSeparateTab) {
new Setting(containerEl)
.setName("Sidebar tab name")
.setDesc("If empty, a default name is used.")
.addText(text => text
.setPlaceholder("e.g., Related notes")
.setValue(this.workingRule.sidebarTabName || "")
.onChange(value => {
this.workingRule.sidebarTabName = value;
})
);
// NEW: Auto-focus toggle
new Setting(containerEl)
.setName("Auto-focus tab when content matches")
.setDesc("Automatically select this tab in the sidebar/drawer when the active note matches this rule. On mobile, this ensures the tab is immediately visible upon swiping open the drawer.")
.addToggle(toggle => toggle
.setValue(this.workingRule.autoFocusSidebarTab ?? false)
.onChange(value => {
this.workingRule.autoFocusSidebarTab = value;
})
);
}
}
3. Update updateAllSidebarViews() in main.ts
When refreshing sidebar views, check if auto-focus is requested and activate the tab:
async updateAllSidebarViews(): Promise<void> {
const mainLeaves = this.app.workspace.getLeavesOfType(VIRTUAL_CONTENT_VIEW);
for (const leaf of mainLeaves) {
if (leaf.view instanceof VirtualContentView) {
leaf.view.update();
}
}
for (let index = 0; index < this.settings.rules.length; index++) {
const rule = this.settings.rules[index];
if (rule.renderLocation === "sidebar" && rule.showInSeparateTab) {
const viewId = this.getSeparateViewId(index);
const leaves = this.app.workspace.getLeavesOfType(viewId);
for (const leaf of leaves) {
if (leaf.view instanceof VirtualContentView) {
leaf.view.update();
}
}
// Auto-focus logic:
if (rule.autoFocusSidebarTab) {
const contentObj = this.getSeparateTabContent(viewId);
if (contentObj && contentObj.content && contentObj.content.trim()) {
let targetLeaf = leaves.length > 0 ? leaves[0] : null;
// Lazily create the leaf in the right sidebar if it doesn't exist yet
if (!targetLeaf && this.app.workspace.getRightLeaf) {
const newLeaf = this.app.workspace.getRightLeaf(false);
if (newLeaf) {
await newLeaf.setViewState({ type: viewId, active: false });
targetLeaf = newLeaf;
}
}
// Select tab in container without forcing drawer open
if (targetLeaf && targetLeaf.parent) {
if (typeof (targetLeaf.parent as any).selectTab === "function") {
(targetLeaf.parent as any).selectTab(targetLeaf);
} else if (Array.isArray((targetLeaf.parent as any).children)) {
const tabIdx = (targetLeaf.parent as any).children.indexOf(targetLeaf);
if (tabIdx !== -1) {
(targetLeaf.parent as any).currentTab = tabIdx;
}
}
}
}
}
}
}
}
Why this is safe
- Zero UI flicker:
selectTab() only mutates the active index of the parent tab container (WorkspaceTabs / WorkspaceMobileDrawer). It does not trigger unprompted popovers or viewport shifts.
- Opt-in behavior: By defaulting
autoFocusSidebarTab to false, existing workflows and users' tab states remain completely unaffected unless explicitly turned on.
- No performance penalty: The check only runs on file switch (
updateAllSidebarViews), which already iterates through active sidebar rules.
[Feature Request] Add "Auto-focus tab when content matches" toggle for separate sidebar tabs (Mobile drawer ergonomics)
Problem / Motivation
When using Virtual Content with
renderLocation: "sidebar"andshowInSeparateTab: true", the content is rendered into a dedicated sidebar tab (e.g.,virtual-content-separate-view-X).This works great, but introduces a UX friction point—especially on Obsidian Mobile:
Proposed Solution
Add an optional toggle under sidebar rule settings:
Implementation Details & Code
Here is the implementation that can be added to the plugin:
1. Extend the
Ruleinterface & defaultsIn rule type definitions:
In default settings / rule sanitization:
2. Add Setting Toggle in
RuleModalInside
renderLocationSpecificControls(containerEl: HTMLElement):3. Update
updateAllSidebarViews()inmain.tsWhen refreshing sidebar views, check if auto-focus is requested and activate the tab:
Why this is safe
selectTab()only mutates the active index of the parent tab container (WorkspaceTabs/WorkspaceMobileDrawer). It does not trigger unprompted popovers or viewport shifts.autoFocusSidebarTabtofalse, existing workflows and users' tab states remain completely unaffected unless explicitly turned on.updateAllSidebarViews), which already iterates through active sidebar rules.