How to make a toolbar in Google Chrome?
Asked Answered
B

4

26

I'm exploring Google Chrome extensions for the first time. I would like to create what appears as a toolbar along the top of the page when you click the extension icon, much like the StumbleUpon toolbar.

I can't see how to do this. The examples mainly show a popup.html, and not a fixed toolbar.

Blanketyblank answered 13/7, 2011 at 15:45 Comment(3)
while you cannot add toolbars to chrome, you CAN add buttons. And that would would give you what you want. check this example of extensions creation lifehacker.com/5857721/how-to-build-a-chrome-extensionMarillin
You've only asked for Chrome, but would you be open to a cross-browser extension that gives you a toolbar in Chrome, IE, Firefox, and Safari, and allows you to communicate between the toolbar and the extension script? You could restrict it to just the Chrome extension if you didn't wish to target all browsers, but you would have the flexibility to go to any of them. If that's an option I'll post the code in an answer here and how to do that. I can also provide examples of how to do cross domain requests and give you a browser button as well. Let me know if that's what you're looking for.Ananna
Look at this Chrome screenshot: howtogeek.com/138516/…Britteny
B
50

Although this answer shows two ways to create a toolbar in Chrome, I strongly recommend using page action or browser action badges. These do not take as much space as toolbars, and can also be used to show a panel on click, and even get temporary host permissions to interact with the page.

The chrome.infobars API

This section used to show a demo using the chrome.infobars API. This API has never been to the stable channel, and will be removed; do not use it.

The chrome.sidebar API

There was a proposal in 2015 for a sidebar API, as an alternative to the chrome.infobars (described above). But this idea was rejected in 2016 in order to prioritize "Chrome’s core value of simplicity" (source).

It seems that there is no way to make an "advanced" tool bar in Chrome without placing it in the document window.

Content scripts

Creation of toolbars using content scripts is tricky. You have to insert code in the page, and even modify the structure of the document, which could break some pages on the internet.

To create a toolbar using content scripts, the following steps have to be taken:

  1. Execute a content script on the page which runs the next two steps.
  2. Insert the toolbar (<iframe> - explained later).
  3. Shift the content of the page.

Step 1 is easy, see my previous example or read the documentation of content scripts.

Step 2: Insert the toolbar

To minimize styling conflicts, and to prevent the page from using your toolbar, insert an iframe. Unlike the previous method, you do not directly have access to the extension API (because the embedded page is neither a content script, nor a page running in the extension's process).

Inserting the toolbar:

add-toolbar.js (content script)

var height = '40px';
var iframe = document.createElement('iframe');
iframe.src = chrome.runtime.getURL('toolbar.html');
iframe.style.height = height;
iframe.style.width = '100%';
iframe.style.position = 'fixed';
iframe.style.top = '0';
iframe.style.left = '0';
iframe.style.zIndex = '938089'; // Some high value
// Etc. Add your own styles if you want to
document.documentElement.appendChild(iframe);

Now create a file called toolbar.html and add it to the "web_accessible_resources" section of your manifest file. This file is going to used at the spot of the toolbar, feel free to do anything non-evil with it. Just keep in mind that it acts like a normal web page, it literally does not have access to any of the Chrome APIs.

Step 3: Shifting the content

So far, you've only added a frame to the page. There's one problem: The content on the page is partially hidden. That is not very nice. There are several ways to fix this, I choose to use CSS transforms, because it's relatively easy to use, and most pages don't use this property on the body element.

// continuing add-toolbar.js
var bodyStyle = document.body.style;
var cssTransform = 'transform' in bodyStyle ? 'transform' : 'webkitTransform';
bodyStyle[cssTransform] = 'translateY(' + height + ')';

translateY causes the body to shift down, including those child elements with position:fixed. Because we've appended the iframe to the root element, outside the <body> tag, the element is not affected.

I want to use extension APIs in the toolbar!

Unfortunately, Chrome treats the embedded html page as a non-privileged extension page. You can only use some of the extension APIs (similar to content scripts).

Another option is to load a page from your server, then execute a content script on that specific page. Set up a Cache manifest to ensure that your toolbar is still available if the user isn't on a network.

Bulahbulawayo answered 24/6, 2013 at 15:44 Comment(12)
Thankyou for you help and thanks for the time you spent writing this awesum answerCompetitive
@ShikataGaNai You're welcome. Why did you want to create a toolbar? There might be a better alternative to it. Toolbars are generally a really bad choice for Chrome extensions.Bulahbulawayo
-webkit-transform doesn't seem to work correctly with facebook, is there any alternative I can use to push the content down ? See my question here #17305778 @Rob WCompetitive
@RobW, thanks for your answer! Half a year has passed since your writeup about this experimental API; I have a followup question, if you will: #21512526Riannon
thanks so much, I followed this example and don't understand your last comment about using localStorage and postMessage in order to use extension APIs. I'm using some chrome APIs in my toolbar, and chrome.runtime.sendMessage has sufficed for getting data or making calls to the chrome APIs so long as it's handled properly in your background scriptChiliasm
Ah sorry, misread that. Deleting the commentary in a couple of minutes.Highgrade
Sadly there is a bug in Chrome that will break every fixed element in the body of the page. code.google.com/p/chromium/issues/detail?id=20574Secondbest
@Secondbest That's not a bug, but a feature. And in this case, exactly what you want, because you want to shift the viewport down (including fixed-size elements). Unfortunately sites like YouTube and Facebook use JavaScript to have a dynamic top bar, and these calculations are confused by the transformation. YouTube's toolbar disappears, and Facebook's toolbar is no longer sticky.Bulahbulawayo
@RobW Thanks for the quick response! The problem is, that every fixed element in the body will be positioned absolute. That breaks Topbars, Affixes, Parallax Sites and many more. But I have to admit your answer is still the best I can think of right now. Thanks!Secondbest
@RobW This is great, seriously! One question though, is it possible to get this to run only when directed? I want to create the toolbar only when a user clicks the notification. Could this be done?Mail
@RobW I can't edit my question one above, but I have found an answer for anyone else that is looking. chrome.tabs.executeScript(null, { file : "header.js"});Mail
How can i access parent DOM from toolbar.html & i need to communicate with the background.js from toolbar. How can i do?Duckett
L
3

Chrome API doesn't have any toolbar widget to assist you. You would need to manually create and position a toolbar div on a page. You can do this by utilizing content scripts, which allow you to inject javascript and css to pages.

Laparotomy answered 13/7, 2011 at 19:34 Comment(0)
A
0

This gives you a stumble-upon-like browser extension for a variety of browsers, although you can limit the download to just chrome if you wish.

Installers

General install page (provides an executable that can be signed if you are on windows to ease the installation process):

http://crossrider.com/apps/35180/install_page

Specific installs:

Crossrider also makes it easy to publish to chrome store as well and provides an easy way to sign your extension for executable downloads on windows.

Info

Here are the docs for the API, its quite extensive for a cross-browser solution:

http://docs.crossrider.com/

In the code below I'm not putting the html & css because there are limits to the number of characters for answers. However, if that looks good, you can either open it up (crx's are zips, just rename extension to .zip) to get the css and html inside or we can figure out a way for me to send it to you. Note that I'm injecting the HTML and CSS into the page.

I usually write the css and html, then minify both (http://cssminifier.com/ and http://www.willpeavy.com/minifier/), then I take the minified output and I use a string escape tool like http://www.htmlescape.net/stringescape_tool.html to escape it so that it can be put into the extension code, as you want that to be as fast as possible, given that its an extension, not a web page of course.

So, if this looks good, go to crossrider.com, set up an account (it is 100% free), and paste these files in the appropriate places and put in the minified/escaped HTML and CSS you need, replacing the stuff in the cssstr and htmlstr in the extension.js below.

Code

extension.js:

appAPI.ready(function($) {
    // Place your code here (you can also define new functions above this scope)
    // The $ object is the extension's jQuery object

    // Adds a listener that handle incoming messages
    var lid = appAPI.message.addListener(function(msg) {
        switch(msg.action) {
            case 'SHOWEXAMPLEBAR': 
            $('#examplebar-toolbar').show();
                break;
            case 'HIDEEXAMPLEBAR': 
                $('#examplebar-toolbar').hide();
                break;
            default: 
                break;
         }
    });

    // Add toolbar (not included here due to size - be sure it is escaped)
    var cssstr = '/* The CSS of your toolbar */';

    // Add toolbar HTML (not included here due to size - be sure it is escaped)
    var htmlstr = '\x3C!-- the html of your toolbar --\x3E';

    $('\x3Cstyle\x3E'+cssstr+'\x3C/style\x3E' + htmlstr).prependTo('body');
    $('#examplebar-close').click(function() {
        //Tell the background to change its buttonstate:
        $('#examplebar-toolbar').hide();
        appAPI.message.toBackground({action: "HIDEEXAMPLEBAR"});
    });
});

background.js:

// Note: the $ variable that represents the jQuery object is not available
//       in the background scope
appAPI.ready(function() {
    // Global variable to hold the toggle state of the button
    var buttonState = true;

    // Sets the initial browser icon
    appAPI.browserAction.setResourceIcon('button.png');

    // Sets the tooltip for the button
    appAPI.browserAction.setTitle('Bar');

    // Sets the text and background color for the button
    if (appAPI.browser.name !== 'safari') {
        appAPI.browserAction.setBadgeText('bar');
        appAPI.browserAction.setBadgeBackgroundColor([255,0,0,50]);
    }else{
        // Safari only supports numeric characters
        // and has a fixed background color
        appAPI.browserAction.setBadgeText('1234');
    }

    // Sets the initial onClick event handler for the button
    appAPI.browserAction.onClick(function(){
        if (buttonState) {
            //Hide the toolbar by notifying the extension code:
            appAPI.message.toAllTabs({action: "HIDEEXAMPLEBAR"});
            if (appAPI.browser.name !== 'safari') {
            // Sets the text and background color for the button
            // using the optional background parameter
                appAPI.browserAction.setBadgeText('helo', [0,0,255,255]);
                // Sets the icon to use for the button.
                appAPI.browserAction.setResourceIcon('button.png');
            } else {
                // Safari only supports numeric characters,
                // has a fixed background color,
                // and can only use the extension's icon
                appAPI.browserAction.setBadgeText('4321');
            }
        } else {
            appAPI.message.toAllTabs({action: "SHOWEXAMPLEBAR"});
            // Remove the badge from the button
            appAPI.browserAction.removeBadge();

            if (appAPI.browser.name !== 'safari'){
                // Reset the icon for the image
                appAPI.browserAction.setResourceIcon('button.png');
            }
        }

        // Toggle the state
        buttonState = !buttonState;
    });

    // Adds a listener that handle incoming messages
    var lid = appAPI.message.addListener(function(msg) {
        switch (msg.action) {
            case 'HIDEEXAMPLEBAR': 
            buttonState = !buttonState;
            break;
            default:
                break;
        }
    });    
});

Notes

Also note that jQuery is automatically available in the extension scope, so you get that for free along with the API's. And, if you want to inject into an iframe, be sure not to forget to enable iframes in the settings.

For the community support site: https://getsatisfaction.com/crossrider

They are very responsive and can help you out when you run into trouble.

Ananna answered 25/6, 2013 at 0:58 Comment(2)
Since cross-rider does not provide built-in toolbars, so there's little advantage in using it over the Chrome API. Firefox, Safari, Internet Explorer and Opera (before 15) provide native APIs for creating toolbars. The method in this answer is basically an application of serg's answer, within just another layer (a framework). One should really be using an iframe for custom toolbars, because the current proposed solution is prone to failure, because it can be controlled/styled by the page.Bulahbulawayo
Either way, whatever works best. It takes about 20 minutes to do that app for all platforms so fortunately there is no investment lost. I'd say advantages are: single code-base, same API for all platforms, near zero effort, to name a few. But whatever works best, I'm all about the right tools for the right job. And iframes are simple with crossrider, as I mentioned in the notes at the bottom. I mean why bother with all the nuances of XPI's versus CRX's versus BHO's if you don't have to? Certainly if there is some functionality you need that only Chrome offers... but if not why bother?Ananna
I
0

The iframe may be restricted but is allowed to send messages. So there is a way to use the extension APIs with the iframe. First step send a message to Backend (Service Worker in Manifest V3). Then send a message back to all tabs (use try catch if there is no listener etc). This also send the message to add-Toolbar.js and your iframe. (So i have a resipiend id in the message) In add-Toolbar.js process the message and do the api calls there. As add-Toolbar.js is in normal scope, this is allowed. If you have a responds you want to process in the iframe, just send it back, through the backend to the iframe.

Interinsurance answered 31/5, 2023 at 20:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.