Window controls
Min, max, close, traffic lights.
Polishing the window controls — OS-conventional layouts, the unmaximize state, double-click-to-maximize, the edge cases users will report.
Windows vs. macOS controls — different conventions
- Windows: Minimise / Maximise / Close on the RIGHT, in that order. Square boxes, ~12-14px icons.
- macOS: Close / Minimise / Zoom on the LEFT, colored traffic lights (red / yellow / green).
Wails ships the native OS traffic lights on macOS if options.Mac isn't set to hide them. The simplest approach: use Wails's defaults on Mac, draw your own on Windows.
OS detection in React
import { Environment } from '../../wailsjs/runtime/runtime'let cachedOS: 'windows' | 'darwin' | 'linux' | null = nullexport async function detectOS() {if (cachedOS) return cachedOSconst env = await Environment()cachedOS = env.platform as anyreturn cachedOS}
Now your titlebar can render OS-appropriate controls or hide them entirely on Mac (Wails handles the traffic lights).
Double-click to maximise
Standard convention — double-click the titlebar maximises / unmaximises. Wire it:
<divstyle={{ '--wails-draggable': 'drag' } as any}onDoubleClick={WindowToggleMaximise}className="h-10 flex items-center justify-between px-4 ...">...
One line. Now power users have the shortcut they expect.
Tracking maximised state for the icon swap
Convention: the maximise button shows a single square when the window is normal, two stacked squares (or a restore icon) when maximised. Listen to the Wails event:
import { EventsOn } from '../../wailsjs/runtime/runtime'export function useIsMaximised() {const [max, setMax] = useState(false)useEffect(() => {const cleanup = EventsOn('wails:window:maximise', () => setMax(true))const cleanup2 = EventsOn('wails:window:unmaximise', () => setMax(false))return () => { cleanup(); cleanup2() }}, [])return max}
const isMax = useIsMaximised()<WinBtn onClick={WindowToggleMaximise}>{isMax ? <Restore /> : <Square />}</WinBtn>
Quit() ends the process. Some apps want close-to-tray instead (Slack, Discord — clicking X hides the window but the process stays). Wire that with the OnBeforeClose hook in main.go.Keyboard shortcuts
- Cmd/Ctrl+W — close window. Wire via Wails accelerators or with an HTML keyboard listener.
- Cmd/Ctrl+M — minimise. macOS does this automatically; Wails has it.
- F11 — fullscreen toggle. Wire to
WindowFullscreen().
Edge cases users WILL report
- Window remembers wrong size on relaunch. Save the geometry on close, restore on startup. Wails has
WindowGetSize / WindowSetPositionfor this. - App restored on a disconnected monitor. Detect off-screen position; reset to centre.
- HiDPI / scale 200%. Test on a high-DPI display. Pixel measurements that look fine at 100% can blur at 200%.
Quick check
Try it
For chapter 3's assignment, polish the titlebar to production quality:
- Add the OS detection — show OS-appropriate controls.
- Add double-click-to-maximize.
- Swap the maximize icon between single-square and restore-icon based on state.
- Save + restore the window size on close + relaunch.
- Test on at least one OS other than your dev machine (Hyper-V Windows VM if you're on Mac, OrbStack macOS if you're on Linux).
What's next
Chapter 4 — In-app auto-update. The most impactful feature for a shipped desktop app. Bug fixes land without users having to re-download installers.
Spot a typo? Have an idea?
Help us improve this lesson. One click opens a GitHub issue with the lesson URL pre-filled — suggest clearer wording, report a bug, or request more depth. The course keeps improving thanks to learners like you.
Suggest an improvement on GitHub