Inject scripts into the active tab  |  Get started  |  Chrome for Developers Skip to main content Docs Build with Chrome Learn how Chrome works, participate in origin trials, and build with Chrome everywhere. Web Platform Capabilities ChromeDriver Extensions Chrome Web Store Chromium Web on Android Origin trials Release notes Productivity Create the best experience for your users with the web's best tools. DevTools Lighthouse Chrome UX Report Accessibility Modern Web Guidance Get things done quicker and neater, with our ready-made libraries. Workbox Puppeteer Experience Design a beautiful and performant web with Chrome. AI Performance CSS and UI Identity Payments Privacy and security Resources More from Chrome and Google. All documentation Baseline web.dev PageSpeed Insights audit Isolated Web Apps (IWA) Case studies Blog New in Chrome / English Deutsch Español – América Latina Français Indonesia Italiano Nederlands Polski Português – Brasil Tiếng Việt Türkçe Русский עברית العربيّة فارسی हिंदी বাংলা ภาษาไทย 中文 – 简体 中文 – 繁體 日本語 한국어 Sign in Docs Chrome Extensions Get started Overview Get Started Develop How To AI Reference API Permissions Manifest Samples Chrome Web Store Prepare your Extension Publish in the Chrome Web Store Program Policies Docs More Overview Get Started Develop How To AI Reference More Samples Chrome Web Store More Case studies Blog New in Chrome Get started Introduction Hello World Run scripts on every page Inject scripts into the active tab Handle events with service workers Manage tabs Debug extensions Build with Chrome Web Platform Capabilities ChromeDriver Extensions Chrome Web Store Chromium Web on Android Origin trials Release notes Productivity DevTools Lighthouse Chrome UX Report Accessibility Modern Web Guidance Workbox Puppeteer Experience AI Performance CSS and UI Identity Payments Privacy and security Resources All documentation Baseline web.dev PageSpeed Insights audit Isolated Web Apps (IWA) API Permissions Manifest Prepare your Extension Publish in the Chrome Web Store Program Policies Home Docs Chrome Extensions Get started Inject scripts into the active tab Stay organized with collections Save and categorize content based on your preferences. This tutorial builds an extension that simplifies the styling of the Chrome extension and Chrome Web Store documentation pages, so that they're easier to read. In this guide, we explain how to do the following: Use the extension service worker as the event coordinator. Preserve user privacy through the "activeTab" permission. Run code when the user clicks the extension toolbar icon. Insert and remove a stylesheet using the Scripting API. Use a keyboard shortcut to execute code. Before you start This guide assumes that you have basic web development experience. Check out Hello World for an introduction to the extension development workflow. Build the extension To start, create a new directory called focus-mode to hold the extension files. You can download the complete source code on GitHub. Step 1: Add the extension data and icons Create a manifest.json file. Copy and paste the following code: { "manifest_version": 3, "name": "Focus Mode", "description": "Enable focus mode on Chrome's official Extensions and Chrome Web Store documentation.", "version": "1.0", "icons": { "16": "images/icon-16.png", "32": "images/icon-32.png", "48": "images/icon-48.png", "128": "images/icon-128.png" } } Create an images folder, then download the icons into it. Tip: Learn more about the manifest keys and icons in our tutorial: Run scripts on every page. Step 2: Initialize the extension Extensions can monitor browser events in the background using the extension's service worker. Service workers are special JavaScript environments that handle events and terminate when they're not needed. Start by registering the service worker in the manifest.json file: { ... "background": { "service_worker": "background.js" }, ... } Create a file called background.js and add the following code: chrome.runtime.onInstalled.addListener(() => { chrome.action.setBadgeText({ text: "OFF", }); }); The first event our service worker will listen for is runtime.onInstalled(). This method allows the extension to set an initial state or complete some tasks on installation. Extensions can use the Storage API and IndexedDB to store the application state. In this case, since we're only handling two states, we use the action's badge text to track whether the extension is 'ON' or 'OFF'. Key Term: action's badge is a banner, on top of the extension action (toolbar icon). Step 3: Enable the extension action The extension action controls the extension's toolbar icon. When the user selects the extension icon, it either runs code (like in this example) or displays a popup. Add the following code to declare the extension action in the manifest.json file: { ... "action": { "default_icon": { "16": "images/icon-16.png", "32": "images/icon-32.png", "48": "images/icon-48.png", "128": "images/icon-128.png" } }, ... } Use the activeTab permission to protect user privacy The activeTab permission grants the extension temporary ability to execute code on the active tab. It also allows access to sensitive properties of the current tab. This permission is enabled when the user invokes the extension. In this case, the user invokes the extension by clicking on the extension action. 💡 What other user interactions enable the activeTab permission in my own extension? Pressing a keyboard shortcut combination. Selecting a context menu item. Accepting a suggestion from the omnibox. Opening an extension popup. The "activeTab" permission allows users to purposefully choose to run the extension on the focused tab; this way, it protects the user's privacy. Another benefit is that it does not trigger a permission warning. To use the "activeTab" permission, add it to the manifest's permission array: { ... "permissions": ["activeTab"], ... } Step 4: Track the state of the current tab After the user clicks the extension action, the extension will check if the URL matches a documentation page. Next, it will check the state of the current tab and set the next state. Add the following code to background.js: const extensions = 'https://developer.chrome.com/docs/extensions'; const webstore = 'https://developer.chrome.com/docs/webstore'; chrome.action.onClicked.addListener(async (tab) => { if (tab.url.startsWith(extensions) || tab.url.startsWith(webstore)) { // Retrieve the action badge to check if the extension is 'ON' or 'OFF' const prevState = await chrome.action.getBadgeText({ tabId: tab.id }); // Next state will always be the opposite const nextState = prevState === 'ON' ? 'OFF' : 'ON'; // Set the action badge to the next state await chrome.action.setBadgeText({ tabId: tab.id, text: nextState, }); } }); Step 5: Add or remove the stylesheet Now it's time to change the layout of the page. Create a file named focus-mode.css and include the following code: * { display: none !important; } html, body, *:has(article), article, article * { display: revert !important; } [role='navigation'] { display: none !important; } article { margin: auto; max-width: 700px; } Insert or remove the stylesheet using the Scripting API. Start by declaring the "scripting" permission in the manifest: { ... "permissions": ["activeTab", "scripting"], ... } Success: The Scripting API does not trigger a permission warning. Finally, in background.js add the following code to change the page layout: ... if (nextState === "ON") { // Insert the CSS file when the user turns the extension on await chrome.scripting.insertCSS({ files: ["focus-mode.css"], target: { tabId: tab.id }, }); } else if (nextState === "OFF") { // Remove the CSS file when the user turns the extension off await chrome.scripting.removeCSS({ files: ["focus-mode.css"], target: { tabId: tab.id }, }); } } }); Tip: You can use scripting.executeScript() to inject JavaScript, instead of adding a stylesheet. (Optional) Assign a keyboard shortcut Just for fun, add a shortcut to make it easier to enable or disable focus mode. Add the "commands" key to the manifest. { ... "commands": { "_execute_action": { "suggested_key": { "default": "Ctrl+B", "mac": "Command+B" } } } } The "_execute_action" key runs the same code as the action.onClicked() event, so no additional code is needed. Test that it works Verify that the file structure of your project looks like the following: Load your extension locally To load an unpacked extension in developer mode, follow the steps in Hello World. Test the extension Open any of the following pages: Welcome to the Chrome Extension documentation Publish in the Chrome Web Store Scripting API Then, click the extension action. If you set up a keyboard shortcut, you can test it by pressing Ctrl+B or Cmd+B. It should go from this: Focus Mode extension off To this: Focus Mode extension on Potential enhancements Based on what you've learned today, try to accomplish any of the following: Improve the CSS stylesheet. Assign a different keyboard shortcut. Change the layout of your favorite blog or documentation site. Keep building Congratulations on finishing this tutorial 🎉. Continue leveling up your skills by completing other tutorials on this series: Extension What you'll learn Reading time Insert an element on a specific set of pages automatically. Tabs Manager Create a popup that manages browser tabs. Continue exploring We hope you enjoyed building this Chrome extension and are excited to continue your extension development learning journey. We recommend the following learning paths: The developer's guide has dozens of additional links to pieces of documentation relevant to advanced extension creation. Extensions have access to powerful APIs beyond what's available on the open web. The Chrome APIs documentation walks through each API. Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates. Last updated 2022-10-04 UTC. [[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2022-10-04 UTC."],[],[]] Contribute File a bug See open issues Related content Chromium updates Case studies Archive Podcasts & shows Follow @ChromiumDev on X YouTube Chrome for Developers on LinkedIn RSS Terms Privacy Manage cookies English Deutsch Español – América Latina Français Indonesia Italiano Nederlands Polski Português – Brasil Tiếng Việt Türkçe Русский עברית العربيّة فارسی हिंदी বাংলা ภาษาไทย 中文 – 简体 中文 – 繁體 日本語 한국어