Skip to main content

Tab Management

Glide provides powerful APIs for managing browser tabs programmatically. This guide covers common tab management workflows and patterns.

Tab Visibility

Native Tab Bar

Control the visibility of Firefox’s built-in tab bar:
// Hide native tabs
glide.o.native_tabs = "hide";

// Auto-hide tabs (show on hover)
glide.o.native_tabs = "autohide";

// Always show tabs (default)
glide.o.native_tabs = "show";
The autohide option does not currently work on macOS.

Custom Styling

Hide the tab bar completely with CSS:
glide.styles.add(css`
  #TabsToolbar {
    visibility: collapse !important;
  }
`);
For vertical tabs, adjust the collapsed width:
glide.o.native_tabs = "autohide";
glide.styles.add(css`
  :root {
    --uc-tab-collapsed-width: 2px;
  }
`);

Tab Querying

Get Active Tab

Retrieve the currently focused tab:
const tab = await glide.tabs.active();
console.log(tab.url);
console.log(tab.id);
This is equivalent to:
const tabs = await browser.tabs.query({ active: true, currentWindow: true });
const tab = tabs[0];

Find Specific Tabs

Find the first tab matching a query:
const tab = await glide.tabs.get_first({ 
  url: "*://github.com/*" 
});

if (tab?.id) {
  await browser.tabs.update(tab.id, { active: true });
}
Query all matching tabs:
const tabs = await glide.tabs.query({ 
  title: "Example Domain" 
});

console.log(`Found ${tabs.length} tabs`);

Tab Operations

Creating Tabs

Create a new tab:
glide.keymaps.set("normal", "<leader>t", async () => {
  await browser.tabs.create({
    url: "https://example.com",
    active: true
  });
});
Create tab in background:
await browser.tabs.create({
  url: "https://example.com",
  active: false
});

Switching Tabs

Switch to a specific tab:
glide.keymaps.set("normal", "gt", async () => {
  const tab = await glide.tabs.get_first({ url: "*://example.com/*" });
  if (tab?.id) {
    await browser.tabs.update(tab.id, { active: true });
  }
}, { description: "[g]o to example.com tab" });
Cycle through tabs:
// Next tab
glide.keymaps.set("normal", "gt", "tab_next");

// Previous tab
glide.keymaps.set("normal", "gT", "tab_prev");

Closing Tabs

Close current tab:
glide.keymaps.set("normal", "d", "tab_close");
Close specific tabs:
glide.keymaps.set("normal", "<leader>d", async () => {
  const tabs = await glide.tabs.query({ url: "*://example.com/*" });
  const ids = tabs.map(t => t.id).filter(Boolean);
  if (ids.length > 0) {
    await browser.tabs.remove(ids);
  }
});

Unloading Tabs

Unload tabs to free memory without closing them:
glide.keymaps.set("normal", "<leader>u", async () => {
  const tabs = await glide.tabs.query({ 
    active: false,
    currentWindow: true 
  });
  
  // Get tab IDs (excluding current tab)
  const ids = tabs.map(t => t.id).filter(Boolean);
  
  if (ids.length > 0) {
    await glide.tabs.unload(...ids);
  }
});
You cannot unload the currently active tab. Attempting to do so will throw an error.

Tab Organization

Grouping by Domain

glide.keymaps.set("normal", "<leader>g", async () => {
  const tabs = await glide.tabs.query({ currentWindow: true });
  
  const groups = new Map<string, typeof tabs>();
  
  for (const tab of tabs) {
    if (!tab.url) continue;
    const domain = new URL(tab.url).hostname;
    if (!groups.has(domain)) {
      groups.set(domain, []);
    }
    groups.get(domain)!.push(tab);
  }
  
  console.log(`Found ${groups.size} unique domains`);
});

Pin/Unpin Tabs

glide.keymaps.set("normal", "<leader>p", async () => {
  const tab = await glide.tabs.active();
  await browser.tabs.update(tab.id, { pinned: !tab.pinned });
});

New Tab Configuration

Custom New Tab Page

Set the URL loaded when creating new tabs:
// Set to a local file
glide.o.newtab_url = "file:///path/to/page.html";

// Set to a website
glide.o.newtab_url = "https://example.com";

// Default Firefox new tab
glide.o.newtab_url = "about:newtab";

Homepage Configuration

Set browser homepage:
glide.prefs.set("browser.startup.homepage", "https://example.com");

Advanced Patterns

Tab Context Tracking

Track and restore tab state:
declare global {
  interface GlideGlobals {
    tab_history?: Map<number, string[]>;
  }
}

glide.g.tab_history = new Map();

glide.autocmds.create("UrlEnter", /./, ({ tab_id, url }) => {
  if (!glide.g.tab_history!.has(tab_id)) {
    glide.g.tab_history!.set(tab_id, []);
  }
  glide.g.tab_history!.get(tab_id)!.push(url);
});

Duplicate Tab Detection

Prevent duplicate tabs:
glide.keymaps.set("normal", "<leader>n", async () => {
  const url = "https://example.com";
  const existing = await glide.tabs.get_first({ url });
  
  if (existing?.id) {
    await browser.tabs.update(existing.id, { active: true });
  } else {
    await browser.tabs.create({ url, active: true });
  }
});

Smart Tab Reloading

Reload tabs matching a pattern:
glide.keymaps.set("normal", "<leader>r", async () => {
  const tabs = await glide.tabs.query({ 
    url: "*://localhost:*/*" 
  });
  
  for (const tab of tabs) {
    if (tab.id) {
      await browser.tabs.reload(tab.id);
    }
  }
});

Window Management

Multi-Window Operations

glide.keymaps.set("normal", "<leader>w", async () => {
  const windows = await browser.windows.getAll();
  const currentWindow = windows.find(w => w.focused);
  
  console.log(`Total windows: ${windows.length}`);
  console.log(`Current window ID: ${currentWindow?.id}`);
});

Move Tab to New Window

glide.keymaps.set("normal", "<leader>m", async () => {
  const tab = await glide.tabs.active();
  await browser.windows.create({ tabId: tab.id });
});

Split Views (Experimental)

Split views are experimental in Firefox. There will be bugs.

Creating Split Views

glide.keymaps.set("normal", "<leader>s", async () => {
  const tabs = await glide.tabs.query({ 
    currentWindow: true,
    pinned: false 
  });
  
  if (tabs.length >= 2) {
    const splitView = glide.unstable.split_views.create(
      [tabs[0], tabs[1]]
    );
    console.log(`Created split view: ${splitView.id}`);
  }
});

Checking Split Status

const tab = await glide.tabs.active();
const hasSplit = glide.unstable.split_views.has_split_view(tab);

Separating Split Views

glide.keymaps.set("normal", "<leader>S", async () => {
  const tab = await glide.tabs.active();
  glide.unstable.split_views.separate(tab);
});

Performance Tips

Use glide.tabs.unload() to free memory from inactive tabs without closing them. This is especially useful for tab hoarders.
Batch tab operations when possible to reduce overhead:
const ids = tabs.map(t => t.id).filter(Boolean);
await browser.tabs.remove(ids); // Better than individual removes

See Also

Build docs developers (and LLMs) love