Created
July 13, 2026 19:44
-
-
Save selfagency/3de50b7d7c0f05c32a5cf2a7fab30ca1 to your computer and use it in GitHub Desktop.
default zoom for google docs userscript
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
| // ==UserScript== | |
| // @name Default Zoom for Google Docs/Sheets | |
| // @namespace default-zoom-google-workspace | |
| // @version 1.0 | |
| // @description Automatically sets your preferred zoom level in Google Docs and Sheets on load, by simulating the zoom menu clicks (since Google exposes no API for this). | |
| // @match https://docs.google.com/document/d/* | |
| // @match https://docs.google.com/spreadsheets/d/* | |
| // @grant GM_getValue | |
| // @grant GM_setValue | |
| // @grant GM_registerMenuCommand | |
| // @run-at document-idle | |
| // ==/UserScript== | |
| (function () { | |
| 'use strict'; | |
| const STORAGE_KEY = 'defaultZoomPercent'; | |
| const VALID_ZOOMS = [50, 75, 90, 100, 125, 150, 175, 200]; | |
| const DEFAULT_ZOOM = GM_getValue(STORAGE_KEY, 100); | |
| const MAX_WAIT_MS = 15000; | |
| const POLL_INTERVAL = 200; | |
| // Let user pick/change their preferred zoom via Tampermonkey menu | |
| GM_registerMenuCommand('Set default zoom level…', () => { | |
| const input = prompt( | |
| `Enter default zoom (${VALID_ZOOMS.join(', ')}):`, | |
| String(DEFAULT_ZOOM) | |
| ); | |
| const value = parseInt(input, 10); | |
| if (VALID_ZOOMS.includes(value)) { | |
| GM_setValue(STORAGE_KEY, value); | |
| alert(`Default zoom set to ${value}%. Reload the doc to apply.`); | |
| } else if (input !== null) { | |
| alert('Invalid value. Choose one of: ' + VALID_ZOOMS.join(', ')); | |
| } | |
| }); | |
| // Skip work if already at the desired zoom | |
| function getCurrentZoomButton() { | |
| // Docs/Sheets render the current zoom % as a clickable toolbar control. | |
| // Match by visible text like "100%" rather than brittle dynamic IDs. | |
| const candidates = document.querySelectorAll( | |
| '[role="button"], .goog-inline-block, .docs-icon-button-content' | |
| ); | |
| for (const el of candidates) { | |
| const text = (el.textContent || '').trim(); | |
| if (/^\d{2,3}%$/.test(text)) { | |
| return el; | |
| } | |
| } | |
| return null; | |
| } | |
| function findMenuItemByPercent(percent) { | |
| const items = document.querySelectorAll( | |
| '[role="menuitem"], [role="menuitemradio"], .goog-menuitem' | |
| ); | |
| for (const item of items) { | |
| const text = (item.textContent || '').trim(); | |
| if (text === `${percent}%`) { | |
| return item; | |
| } | |
| } | |
| return null; | |
| } | |
| function clickElement(el) { | |
| if (!el) return false; | |
| el.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, cancelable: true })); | |
| el.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, cancelable: true })); | |
| el.dispatchEvent(new MouseEvent('click', { bubbles: true, cancelable: true })); | |
| return true; | |
| } | |
| function setZoom(percent) { | |
| const zoomButton = getCurrentZoomButton(); | |
| if (!zoomButton) return false; | |
| // Already at target zoom — skip | |
| if (zoomButton.textContent.trim() === `${percent}%`) { | |
| return true; | |
| } | |
| // Open the zoom dropdown | |
| clickElement(zoomButton); | |
| // Wait a tick for the menu to render, then click the matching option | |
| setTimeout(() => { | |
| const menuItem = findMenuItemByPercent(percent); | |
| if (menuItem) { | |
| clickElement(menuItem); | |
| } else { | |
| // Close menu if we couldn't find a match, to avoid leaving it open | |
| document.body.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true })); | |
| } | |
| }, 150); | |
| return true; | |
| } | |
| function waitForToolbarAndApply() { | |
| const start = Date.now(); | |
| const interval = setInterval(() => { | |
| const zoomButton = getCurrentZoomButton(); | |
| if (zoomButton) { | |
| clearInterval(interval); | |
| setZoom(DEFAULT_ZOOM); | |
| } else if (Date.now() - start > MAX_WAIT_MS) { | |
| clearInterval(interval); | |
| console.warn('[Default Zoom] Toolbar zoom control not found, giving up.'); | |
| } | |
| }, POLL_INTERVAL); | |
| } | |
| waitForToolbarAndApply(); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment