Key featuresFeaturesPricingSecurityDocsChangelog
Log inStart for free

Getting Started

  • What is QA Note?
  • Quick Start Guide
  • Install Extension
  • Project Members

Feature Guide

  • Screenshot & Annotation
  • Session Recording
  • Maintenance Reports
  • Issue State Model
  • Multi-issue Windows
  • Storage · DOM Snapshot

Integrations

  • GitHub
  • Commit Keys
  • MCP Server
  • Slack
  • Webhook
  • Vercel
  • Existing Playwright

API Reference

  • Authentication
  • Endpoint Reference
  • Public API v1
  • Error Handling

The issue tracker you use with your AI agent. Your agent fixes; QA Note keeps the record.

Made in Seoul · © 2026 QA Note
ProductKey featuresFeaturesPricingSecurityChangelog
ResourcesDocsMCP guideChrome Extension
CompanyBrandTerms of ServicePrivacy Policy

ffgg|CEO: Songwook Han

Business Registration No.: 746-54-00870[Verify]|E-Commerce License No.: 2024-Seoul Mapo-2178

Address: 5F, 26 World Cup buk-ro 6-gil, Mapo-gu, Seoul, Republic of Korea

Email: support@qanote.app|Hosting Provider: Vercel Inc.

© 2026 QA Note. All rights reserved.

Terms of ServicePrivacy PolicyCookie Policy
  1. Home
  2. /
  3. Docs
  4. /
  5. Feature Guide

Multi-issue Windows

Open multiple issues like apps on a desktop — compare and work side by side.

Table of Contents
  • Desktop Metaphor
  • Title Bar Actions
  • Dedicated Page
  • Collapsed Window Tab Bar
  • Hydration Mismatch Workaround
  • Limits

One issue, one window. Stack several windows on top of the dashboard, drag them around, overlap them, collapse them — the way you treat OS windows. Two screenshots side by side, one issue minimized while you skim another — the workflow falls out naturally.

Desktop Metaphor

The window model deliberately mirrors macOS / Windows window managers. Users already know how to drag the title bar, resize from a corner, double-click to maximize. We reuse those gestures so multi-issue work has zero learning cost.

OS gestureQA Note multi-window
Drag title barMove window
Drag cornerResize window
Double-click title barToggle maximize
Collapse windowSend to the bottom tab bar (Cmd/Ctrl+M)

Windows have z-order. Clicking a window raises it.

Title Bar Actions

The title bar is 36px tall. Left to right:

#ItemIconShortcutAction
1Previous issue‹—Swap to the previous issue in the list (dimmed at the start)
2Next issue›—Swap to the next issue in the list (dimmed at the end)
3Position——QANOTE-16 · 3 / 37 (issue key only when there is no list)
4Title——Truncated. Highlights for 2.2s when a remote edit lands
5Open in full page↗—Switch to /issues/[issueNumber]
6Collapse window−Cmd/Ctrl+MSend to the bottom tab bar
7Maximize ↔ restore⤢—Double-clicking the title bar toggles it too
8Close window×EscRemove the window (the issue stays)

Cmd/Ctrl+M and Esc apply only to the focused (topmost) window, and are ignored while the caret is in an input or editor.

Dedicated Page

Windows are small — data gets compressed. To dig in, hit ↗ on the title bar to switch to the full-screen page (/issues/[issueNumber]). The URL changes, so it's shareable.

The set of open windows is mirrored in the address bar as ?issues=16,12. Copy that URL and the same arrangement comes back.

Collapsed Window Tab Bar

Collapsing a window (the − button or Cmd/Ctrl+M) does not discard it — it moves into a pill-shaped bar centered at the bottom of the screen. Each tab keeps the issue key and title, and a {collapsed} / 8 counter sits at the right end.

ActionResult
Click a tabExpand the window and focus it
Click the tab's ×Close the window straight from the bar
  • A collapsed window keeps its position and size. Expanding puts it back exactly where it was.
  • The collapsed flag is persisted to localStorage, so it survives a reload.
  • When a bulk action bar is showing, the tab bar shifts one step up to clear it.

Hydration Mismatch Workaround

Window position, size, and open state live in localStorage. Next.js App Router can't read localStorage during SSR, so a naive read on first render causes a hydration mismatch.

The pattern is render empty on first paint, restore inside useEffect.

tsx
"use client";
import { useEffect, useState } from "react";

type WindowState = { id: string; x: number; y: number; w: number; h: number };

export function MultiWindowShell() {
  const [windows, setWindows] = useState<WindowState[]>([]);

  // Restore from localStorage only after first client render → no hydration mismatch
  useEffect(() => {
    const stored = localStorage.getItem("qanote:windows");
    if (stored) setWindows(JSON.parse(stored));
  }, []);

  // Persist on change
  useEffect(() => {
    localStorage.setItem("qanote:windows", JSON.stringify(windows));
  }, [windows]);

  return (
    <div className="multi-window-shell">
      {windows.map((w) => (
        <IssueWindow key={w.id} state={w} />
      ))}
    </div>
  );
}

Server render emits windows = []. Hydration runs, then useEffect fills in the real state. Users see a brief flicker — windows appear a beat late — but no hydration warning.

A next/dynamic import with ssr: false works too. Either way, the rule is server and first client render must match.

Limits

  • Max concurrent windows: 8. With 8 open, opening another issue adds no window — you get a "You can open up to 8 windows" toast instead. Re-opening an issue that is already open is a focus, and is not subject to the cap.
  • Small screens: Windows are clamped into the viewport. Shrink the browser and open windows slide back inside, with width and height reduced to fit.
  • Restore scope: localStorage is per-browser, per-domain. Incognito or a different browser starts empty.
  • Min window size: 320×240. Resize stops there.
  • Not a modal: The page behind is not dimmed and focus is not trapped. You can keep windows open and keep working the list or board behind them.
Previous
Issue State Model
Next
Storage · DOM Snapshot

Table of Contents

  • Desktop Metaphor
  • Title Bar Actions
  • Dedicated Page
  • Collapsed Window Tab Bar
  • Hydration Mismatch Workaround
  • Limits