A Chromium browser extension that gives you customizable keyboard shortcuts for everyday tab, window, and navigation actions — the ones the browser doesn't ship with out of the box (move tab to first/last, create a new tab inside the current tab group, open chrome://flags, and so on).
Built as a Manifest V3 service worker. No UI, no tracking, no permissions beyond what's needed to manipulate tabs.
- Select previous / next tab (with wrap-around)
- Move current tab left / right (respects pinned-tab boundary)
- Move current tab to first / last position
- Reload, duplicate, pin/unpin, mute/unmute, close
- Create a new tab
- Create a new tab inside the current tab group
- Go back / go forward in tab history
- New window
- New incognito window
chrome://extensionschrome://extensions/shortcutschrome://downloadschrome://settingschrome://historychrome://bookmarkschrome://helpchrome://flags
-
Clone the repository and install dependencies:
yarn install
-
Build the extension:
yarn build
-
Open your Chromium-based browser (Chrome, Edge, Brave, Arc, etc.) and go to
chrome://extensions. -
Enable Developer mode.
-
Click Load unpacked and select the generated
dist/folder.
Chrome does not let extensions ship default key bindings, so every command starts unbound. To assign keys:
- Open
chrome://extensions/shortcuts(Shortcutfy itself can open this page once you bind theopen-extensions-shortcutscommand). - Find Shortcutfy in the list and assign whatever combinations you want to each command.
Requires Node.js (LTS — see .nvmrc) and Yarn 4.
| Script | What it does |
|---|---|
yarn build |
Clean build of dist/ — compiles TS, copies manifest.json + icons/. Output is the loadable extension. |
yarn start:dev |
One-shot build, then tsc --watch for incremental rebuilds. Re-run yarn build after manifest/icon edits. |
yarn build:icons |
Regenerates src/icons/{16,32,48,128}.png from src/icon.svg (uses sharp). |
yarn build:commands |
Regenerates the commands block in src/manifest.json from commandDefinitions. |
yarn clean |
Removes dist/ and the TypeScript incremental cache. |
yarn lint |
Runs ESLint with --fix over src/ and scripts/. |
yarn format |
Runs Prettier over .ts sources. |
yarn style |
yarn format && yarn lint in one shot. |
yarn test |
tsc --noEmit — type-checks the whole repo. |
After yarn build, reload the extension in chrome://extensions to pick up changes.
The extension keeps the command list in three synchronized places. To add a command:
- Add an entry to the
Commandenum insrc/enums/index.ts. - Implement the handler (usually in
src/helpers/) and re-export it fromsrc/helpers/index.ts. - Wire it into
commandHandlersinsrc/service-worker.ts. - Add a description for it in
commandDefinitionsinsidesrc/build-manifest-commands.ts, then runyarn build:commandsto updatesrc/manifest.json.
src/
├── service-worker.ts # MV3 background entry — registers chrome.commands listener
├── manifest.json # Extension manifest (declares commands, icons, permissions)
├── icon.svg # Master icon (rendered into PNGs by yarn build:icons)
├── icons/ # Generated PNG icons (16/32/48/128)
├── build-manifest-commands.ts # Regenerates manifest.commands from source (dev-only)
├── enums/ # Command enum (single source of truth for command keys)
├── facades/ # Thin wrappers around chrome.tabs.* used by helpers
└── helpers/ # Command handlers — tabs, windows, browser-url shortcuts
scripts/
├── build.ts # Runs tsc + copies manifest/icons into dist/
└── build-icons.ts # Renders src/icon.svg into PNG sizes
This repository uses Conventional Commits, enforced by commitlint + a Husky commit-msg hook. pre-commit runs lint-staged (ESLint + Prettier) on touched files.
The first publish to the Chrome Web Store is manual (you need to create a developer account and upload shortcutfy-<version>.zip once). After that, every subsequent release is one command — see docs/store/RELEASING.md.
yarn release patch # bumps version, commits, tags
git push origin main --follow-tagsGitHub Actions builds the zip, attaches it to a GitHub Release, and (if Chrome Web Store API credentials are configured) uploads and publishes it.
MIT — see package.json.